Dynamic-Link Libraries

Dynamic-link libraries (DLL) are modules that contain functions and data. A DLL is loaded at run time by its calling modules (.exe or .dll). When a DLL is loaded, it is mapped into the address space of the calling process.

DLLs can define two kinds of functions: exported and internal. The exported functions can be called by other modules. Internal functions can only be called from within the DLL where they are defined. Although DLLs can export data, its data is usually only used by its functions.

DLLs provide a way to modularize applications so that functionality can be updated and reused more easily. They also help reduce memory overhead when several applications use the same functionality at the same time, because although each application gets its own copy of the data, they can share the code.

The Microsoft® Win32® application programming interface (API) is implemented as a set of dynamic-link libraries, so any process that uses the Win32 API uses dynamic linking.

  • About Dynamic-Link Libraries
  • Using Dynamic-Link Libraries
  • Dynamic-Link Library Reference
Microsoft Platform SDK, February 2001 Edition.
This content last built on Thursday, February 08, 2001.


About Dynamic-Link Libraries

Dynamic linking allows a module to include only the information the system needs at load time or run time to locate the code for an exported DLL function. Dynamic linking differs from the more familiar static linking, in which the linker copies a library function's code into each module that calls it.

Types of Dynamic Linking

There are two methods for calling a function in a DLL:

  • In load-time dynamic linking, a module makes explicit calls to exported DLL functions. This requires you to link the module with the import library for the DLL. An import library supplies the system with the information needed to load the DLL and locate the exported DLL functions when the application is loaded. For more information, see Load-Time Dynamic Linking.
  • In run-time dynamic linking, a module uses the LoadLibrary or LoadLibraryEx function to load the DLL at run time. After the DLL is loaded, the module calls the GetProcAddress function to get the addresses of the exported DLL functions. The module calls the exported DLL functions using the function pointers returned by GetProcAddress. This eliminates the need for an import library. For more information, see Using Run-Time Dynamic Linking.

DLLs and Memory Management

Every process that loads the DLL maps it into its virtual address space. After the process loads the DLL into its virtual address, it can call the exported DLL functions.

The system maintains a reference count for each DLL. When a thread loads the DLL, its reference count is incremented by one. When the process terminates, or when the reference count goes to 0 (run-time dynamic linking only), the DLL is unloaded from the virtual address space.

Like any other function, an exported DLL function runs in the context of the thread that calls it. Therefore, the following conditions apply:

  • The threads of the process that called the DLL can use handles opened by a DLL function. Similarly, handles opened by any thread of the calling process can be used in the DLL function.
  • The DLL uses the stack of the calling thread and the virtual address space of the calling process.
  • The DLL allocates memory from the virtual address space of the calling process.


Advantages of Dynamic Linking

Dynamic linking has the following advantages over static linking:

  • Processes that load a DLL at the same base address can use a single DLL simultaneously, sharing a single copy of the DLL code in physical memory. Doing this saves memory and reduces swapping.
  • When the functions in a DLL change, the applications that use them do not need to be recompiled or relinked as long as the function arguments, calling conventions, and return values do not change. In contrast, statically linked object code requires that the application be relinked when the functions change.
  • A DLL can provide after-market support. For example, a display driver DLL can be modified to support a display that was not available when the application was initially shipped.
  • Programs written in different programming languages can call the same DLL function as long as the programs follow the same calling convention that the function uses. The calling convention (such as C, Pascal, or standard call) controls the order in which the calling function must push the arguments onto the stack, whether the function or the calling function is responsible for cleaning up the stack, and whether any arguments are passed in registers. For more information, see the documentation included with your compiler.

A potential disadvantage to using DLLs is that the application is not self-contained; it depends on the existence of a separate DLL module. The system terminates processes using load-time dynamic linking if they require a DLL that is not found at process startup and gives an error message to the user. The system does not terminate a process using run-time dynamic linking in this situation, but functions exported by the DLL are not available to the program.


Dynamic-Link Library Creation

To create a DLL, you must create one or more source code files, and possibly a linker file for exporting the functions. If you plan to allow applications that use your DLL to use load-time dynamic linking, you must also create an import library.

Creating Source Files

The source files contain exported functions, internal functions, and an optional entry-point function for the DLL. You may use any development tools that support the creation of Win32-based DLLs.

If your DLL may be used by a multithreaded application, you should make your DLL "thread-safe" by linking only with libraries that have support for multiple threads. Also, be sure to synchronize access to your global data.

Exporting Functions

How you specify exported functions depends on the tools that you are using for development. Some compilers allow you to export a function directly in the source code by using a modifier in the function declaration. Other times, you must specify exports in a file that you pass to the linker.

For example, using Microsoft Visual C++, there are two possible ways to export DLL functions: with _declspec modifier or with a .DEF file. If you use the _declspec modifier, it is not necessary to use a .DEF file.

For more information about exporting functions, see the documentation included with your development tools.

Creating an Import Library

The import library (.LIB) file contains information the linker needs to resolve external references to exported DLL functions, so the system can locate the specified DLL and exported DLL functions at run time. For example, to call the CreateWindow function, you must link your code with the import library USER32.LIB. The reason is that CreateWindow resides in a system DLL. The file USER32.LIB is the import library used to resolve the call to CreateWindow in your code.

For information about creating import libraries, see the documentation included with your development tools.

Warning Calling the ExitProcess function in a DLL can lead to unexpected application or system errors. Be sure to call ExitProcess from a DLL only if you know which applications or system components will load the DLL and that it is safe to call ExitProcess in this context.


Dynamic-Link Library Entry-Point Function

Every DLL must have an entry point, just as an application does. The system calls the entry-point function whenever processes and threads load or unload the DLL. If you are linking your DLL with a library, such as the C run-time library, it may provide an entry-point function for you, and allow you to provide a separate initialization function. Check the documentation for your run-time library for more information.

If you are providing your own entry-point, see the DllMain function. The name DllMain is a placeholder for a user-defined function. Earlier versions of the SDK documentation used DllEntryPoint as the entry-point function name. You must specify the actual name you use when you build your DLL. For more information, see the documentation included with your development tools.

Calling the Entry-Point Function

The system calls the entry-point function whenever any one of the following events occurs:

  • A process loads the DLL. For processes using load-time dynamic linking, the DLL is loaded during process initialization. For processes using run-time linking, the DLL is loaded before LoadLibrary or LoadLibraryEx returns.
  • A process unloads the DLL. The DLL is unloaded when the process terminates or calls the FreeLibrary function and the reference count becomes zero. If the process terminates as a result of the TerminateProcess or TerminateThread function, the system does not call the DLL entry-point function.
  • A new thread is created in a process that has loaded the DLL. You can use the DisableThreadLibraryCalls function to disable notification when threads are created.
  • A thread of a process that has loaded the DLL terminates normally, not using TerminateThread or TerminateProcess. When a process unloads the DLL, the entry-point function is called only once for the entire process, rather than once for each existing thread of the process. You can use DisableThreadLibraryCalls to disable notification when threads are terminated.

Only one thread at a time can call the entry-point function.

The system calls the entry-point function in the context of the process or thread that caused the function to be called. This allows a DLL to use its entry-point function for allocating memory in the virtual address space of the calling process or to open handles accessible to the process. The entry-point function can also allocate memory that is private to a new thread by using thread local storage (TLS). For more information about thread local storage, see Thread Local Storage.

Entry-Point Function Definition

The DLL entry-point function must be declared with the standard-call calling convention.

Windows NT/2000 or later: If the DLL entry point is not declared correctly, the DLL is not loaded, and the system displays a message indicating that the DLL entry point must be declared with WINAPI.

Windows 95/98/Me: If the DLL entry point is not declared correctly, the DLL is not loaded and the system displays a message titled "Error starting program," which instructs the user to check the file to determine the problem.

In the body of the function, you may handle any combination of the following scenarios in which the DLL entry point has been called:

  • A process loads the DLL (DLL_PROCESS_ATTACH).
  • The current process creates a new thread (DLL_THREAD_ATTACH).
  • A thread exits normally (DLL_THREAD_DETACH).
  • A process unloads the DLL (DLL_PROCESS_DETACH).

Your function should perform only simple initialization tasks, such as setting up thread local storage (TLS), creating synchronization objects, and opening files. It must not call the LoadLibrary function, because this may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, you must not call the FreeLibrary function in the entry-point function, because this can result in a DLL being used after the system has executed its termination code.

Calling Win32 functions other than TLS, synchronization, and file functions may also result in problems that are difficult to diagnose. For example, calling User, Shell, and COM functions can cause access violation errors, because some functions in their DLLs call LoadLibrary to load other system components.

The following example demonstrates how to structure the DLL entry-point function.

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason )
    {
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

Entry-Point Function Return Value

When a DLL entry-point function is called because a process is loading, the function returns TRUE to indicate success. For processes using load-time linking, a return value of FALSE causes the process initialization to fail and the process terminates. For processes using run-time linking, a return value of FALSE causes the LoadLibrary or LoadLibraryEx function to return NULL, indicating failure. (The system immediately calls your entry-point function with DLL_PROCESS_DETACH and unloads the DLL.) The return value of the entry-point function is disregarded when the function is called for any other reason.


Load-Time Dynamic Linking

When the system starts a program that uses load-time dynamic linking, it uses the information in the file to locate the names of the required DLL(s). The system then searches for the DLLs in the following locations, in sequence:

  1. The directory from which the application loaded.
  2. The current directory.
  3. Windows 95/98/Me: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

    Windows NT/2000 or later: The 32-bit Windows system directory. Use the GetSystemDirectory function to obtain the path of this directory.

  4. Windows NT/2000 or later: The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

If the system cannot locate a specified DLL, it terminates the process and displays a dialog box that reports the error. Otherwise, the system maps the DLL modules into the virtual address space of the process and increments the DLL reference count.

The system calls the entry-point function. The function receives a code indicating that the process is loading the DLL. If the entry-point function does not return TRUE, the system terminates the process and reports the error. For more information about the entry-point function, see Dynamic-Link Library Entry-Point Function.

Finally, the system modifies the code of the process to provide starting addresses for the referenced DLL functions.

The DLL is mapped into the virtual address space of the process during its initialization and is loaded into physical memory only when needed.


Run-Time Dynamic Linking

When the application calls the LoadLibrary or LoadLibraryEx functions, the system attempts to locate the DLL using the same search sequence used in load-time dynamic linking (see Load-Time Dynamic Linking). If the search succeeds, the system maps the DLL module into the virtual address space of the process and increments the reference count. If the call to LoadLibrary or LoadLibraryEx specifies a DLL whose code is already mapped into the virtual address space of the calling process, the function simply returns a handle to the DLL and increments the DLL reference count. Note that two DLLs that have the same base file name and extension but are found in different directories are not considered to be the same DLL.

The system calls the entry-point function in the context of the thread that called LoadLibrary or LoadLibraryEx. The entry-point function is not called if the DLL was already loaded by the process through a call to LoadLibrary or LoadLibraryEx with no corresponding call to the FreeLibrary function.

If the system cannot find the DLL or if the entry-point function returns FALSE, LoadLibrary or LoadLibraryEx returns NULL. If LoadLibrary or LoadLibraryEx succeeds, it returns a handle to the DLL module. The process can use this handle to identify the DLL in a call to the GetProcAddress, FreeLibrary, or FreeLibraryAndExitThread function.

The GetModuleHandle function returns a handle used in GetProcAddress, FreeLibrary, or FreeLibraryAndExitThread. The GetModuleHandle function succeeds only if the DLL module is already mapped into the address space of the process by load-time linking or by a previous call to LoadLibrary or LoadLibraryEx. Unlike LoadLibrary or LoadLibraryEx, GetModuleHandle does not increment the module reference count. The GetModuleFileName function retrieves the full path of the module associated with a handle returned by GetModuleHandle, LoadLibrary, or LoadLibraryEx.

The process can use GetProcAddress to get the address of an exported function in the DLL using a DLL module handle returned by either LoadLibrary, LoadLibraryEx, or GetModuleHandle.

When the DLL module is no longer needed, the process can call FreeLibrary or FreeLibraryAndExitThread. These functions decrement the module reference count and unmap the DLL code from the virtual address space of the process if the reference count is zero.

Run-time dynamic linking enables the process to continue running even if a DLL is not available. The process can then use an alternate method to accomplish its objective. For example, if a process is unable to locate one DLL, it can try to use another, or it can notify the user of an error. If the user can provide the full path of the missing DLL, the process can use this information to load the DLL even though it is not in the normal search path. This situation contrasts with load-time linking, in which the system simply terminates the process if it cannot find the DLL.

Run-time dynamic linking can cause problems if the DLL uses the DllMain function to perform initialization for each thread of a process, because the entry-point is not called for threads that existed before LoadLibrary or LoadLibraryEx is called. For an example showing how to deal with this problem, see Using Thread Local Storage in a Dynamic-Link Library.


Dynamic-Link Library Data

Win32-based DLLs can contain global data or local data.

Variable Scope

The default scope of DLL variables is the same as that of variables declared in the application. Global variables in a DLL source code file are global to each process using the DLL. Static variables have scope limited to the block in which they are declared. As a result, each process has its own instance of the DLL global and static variables by default.

Your development tools may allow you to override the default scope of global and static variables. For more information, see the documentation included with your development tools.

Dynamic Memory Allocation

When a DLL allocates memory using any of the memory allocation functions (GlobalAlloc, LocalAlloc, HeapAlloc, and VirtualAlloc), the memory is allocated in the virtual address space of the calling process and is accessible only to the threads of that process.

A DLL can use file mapping to allocate memory that can be shared among processes. For a general discussion of how to use file mapping to create named shared memory, see File Mapping. For an example that uses the DllMain function to set up shared memory using file mapping, see Using Shared Memory in a Dynamic-Link Library.

Thread Local Storage

The thread local storage (TLS) functions enable a DLL to allocate an index for storing and retrieving a different value for each thread of a multithreaded process. For example, a spreadsheet application can create a new instance of the same thread each time the user opens a new spreadsheet. A DLL providing the functions for various spreadsheet operations can use TLS to save information about the current state of each spreadsheet (row, column, and so on). For a general discussion of thread local storage, see Thread Local Storage. For an example that uses the DllMain function to set up thread local storage, see Using Thread Local Storage in a Dynamic-Link Library.

Warning The Visual C++ compiler supports a syntax that enables you to declare thread-local variables: _declspec(thread). If you use this syntax in a DLL, you will not be able to load the DLL explicitly using LoadLibrary or LoadLibraryEx. If your DLL will be loaded explicitly, you must use the thread local storage functions instead of _declspec(thread).


Dynamic-Link Library Redirection

Problems can occur when an application loads a version of a DLL other than the one with which it shipped. Starting with Windows 2000, you can ensure that your application uses the correct version of a DLL by creating a redirection file. The contents of a redirection file are ignored, but its presence forces all DLLs in the application's directory to be loaded from that directory.

The redirection file must be named as follows:

appname.local

For example, if the application's name is editor.exe, the redirection file is named editor.exe.local. You must install editor.exe.local in the same directory that contains editor.exe. You must also install the DLLs in the same directory.

The LoadLibrary and LoadLibraryEx functions change their search sequence if a redirection file is present. If a path is specified and there is a redirection file for the application, these functions search for the DLL in the application's directory. If the DLL exists in the application's directory, these functions ignore the specified path and load the DLL from the application's directory. If the module is not in the application's directory, these functions load the DLL from the specified directory.

For example, an application c:\myapp\myapp.exe calls LoadLibrary using the following path:

c:\program files\common files\system\mydll.dll.

If c:\myapp\myapp.exe.local and c:\myapp\mydll.dll exist, LoadLibrary will load c:\myapp\mydll.dll. Otherwise, LoadLibrary will load c:\program files\common files\system\mydll.dll.

Note It is good practice to install your application's DLLs in the same directory that contains the application, even if you are not using redirection. It ensures that installing your application will not overwrite other copies of the DLL and cause other applications to fail. In addition, other applications will not overwrite your copy of the DLL and cause your application to fail.


Dynamic-Link Library Updates

It is sometimes necessary to replace a DLL with a newer version. Before replacing a DLL, perform a version check to ensure that you are replacing an older version with a newer version. It is possible to replace a DLL that is in use. The method you use to replace DLLs that are in use depends on the operating system you are using.

On Windows NT/Windows 2000, it is not necessary to restart the computer if you perform the following steps:

  1. Use the MoveFileEx function to rename the DLL being replaced. Do not specify MOVEFILE_COPY_ALLOWED, and make sure the renamed file is on the same volume that contains the original file. You could also simply rename the file in the same directory by giving it a different extension.
  2. Copy the new DLL to the directory that contains the renamed DLL. All applications will now use the new DLL.
  3. Use MoveFileEx with MOVEFILE_DELAY_UNTIL_REBOOT to delete the renamed DLL.

Before you make this replacement, applications will use the original DLL until it is unloaded. After you make the replacement, applications will use the new DLL. When you write a DLL, you must be careful to ensure that it is prepared for this situation, especially if the DLL maintains global state information or communicates with other services. If the DLL is not prepared for a change in global state information or communication protocols, updating the DLL will require you to restart the computer to ensure that all applications are using the same version of the DLL.

On Windows 95/98, it is necessary to restart the computer. For more information, see the Remarks section of MoveFileEx.


Using Dynamic-Link Libraries

The following examples demonstrate how to create and use a DLL.

  • Creating a simple dynamic-link library
  • Using load-time dynamic linking
  • Using run-time dynamic linking
  • Using shared memory in a dynamic-link library
  • Using thread local storage in a dynamic-link library


Creating a Simple Dynamic-Link Library

The following example, MYPUTS.C, is the source code needed to create a simple DLL, MYPUTS.DLL. The file MYPUTS.C contains a simple string-printing function called myPuts. The MYPUTS DLL does not define an entry-point function, because it is linked with the C run-time library and has no initialization or cleanup functions of its own to perform.

// File: MYPUTS.C.
// The myPuts function writes a null-terminated string to
// the standard output device.
.

#include <windows.h>

VOID myPuts(LPTSTR lpszMsg)
{
    DWORD cchWritten;
    HANDLE hStdout;

    // Get a handle to the standard output device.

    hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

    // Write a null-terminated string to the standard output device.

    while (*lpszMsg)
        WriteFile(hStdout, lpszMsg++, 1, &cchWritten, NULL);
}

To build the DLL, follow the directions in the documentation included with your development tools.


Using Load-Time Dynamic Linking

After you have created a DLL, you can use it in an application. The following file, LOADTIME.C, is the source code for a simple console application that uses the myPuts function exported from MYPUTS.DLL.

// File: LOADTIME.C.
// A simple program that uses myPuts from MYPUTS.DLL.

#include <windows.h>

VOID myPuts(LPTSTR);   // a function from a DLL

VOID main(VOID)
{
    myPuts("message printed using the DLL function\n");
}

Because LOADTIME.C calls the DLL function explicitly, the module for the application must be linked with the import library MYPUTS.LIB. For more information about building DLLs, see the documentation included with your development tools.


Using Run-Time Dynamic Linking

You can use the same DLL in both load-time and run-time dynamic linking. The following source code produces the same output as the load-time example in the previous section. The program uses the LoadLibrary function to get a handle to MYPUTS.DLL. If LoadLibrary succeeds, the program uses the returned handle in the GetProcAddress function to get the address of the DLL's myPuts function. After calling the DLL function, the program calls the FreeLibrary function to unload the DLL.

The following example illustrates an important difference between run-time and load-time dynamic linking. If the MYPUTS.DLL file is not available, the application using load-time dynamic linking simply terminates. The run-time dynamic linking example, however, can respond to the error.

// File:  RUNTIME.C
// A simple program that uses LoadLibrary and
// GetProcAddress to access myPuts from MYPUTS.DLL.

#include <stdio.h>
#include <windows.h>

typedef VOID (*MYPROC)(LPTSTR);

VOID main(VOID)
{
    HINSTANCE hinstLib;
    MYPROC ProcAdd;
    BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;

    // Get a handle to the DLL module.

    hinstLib = LoadLibrary("myputs");

    // If the handle is valid, try to get the function address.

    if (hinstLib != NULL)
    {
        ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts");

        // If the function address is valid, call the function.

        if (fRunTimeLinkSuccess = (ProcAdd != NULL))
            (ProcAdd) ("message via DLL function\n");

        // Free the DLL module.

        fFreeResult = FreeLibrary(hinstLib);
    }

    // If unable to call the DLL function, use an alternative.

    if (! fRunTimeLinkSuccess)
        printf("message via alternative method\n");
}

Because the program uses run-time dynamic linking, you should not link with the import library when creating the program module.


Using Shared Memory in a Dynamic-Link Library

This section shows how the DLL entry-point function can use a file-mapping object to set up memory that can be shared by processes that load the DLL. The shared DLL memory persists only as long as the DLL is loaded.

The example uses file mapping to map a block of named shared memory into the virtual address space of each process that loads the DLL. To do this, the entry-point function must:

  1. Call the CreateFileMapping function to get a handle to a file-mapping object. The first process that loads the DLL creates the file-mapping object. Subsequent processes open a handle to the existing object. For more information, see Creating a File-Mapping Object.
  2. Call the MapViewOfFile function to map a view into the virtual address space. This enables the process to access the shared memory. For more information, see Creating a File View.
// File:  DLLSHMEM.C.
// The DLL entry-point function sets up shared memory using
// a named file-mapping object.

#include <windows.h>
#include <memory.h>

#define SHMEMSIZE 4096

static LPVOID lpvMem = NULL; // pointer to shared memory

BOOL DllMain(HINSTANCE hinstDLL,  // DLL module handle
    DWORD fdwReason,              // reason called
    LPVOID lpvReserved)           // reserved
{
    HANDLE hMapObject = NULL;  // handle to file mapping
    BOOL fInit, fIgnore;

    switch (fdwReason)
    {
        // The DLL is loading due to process
        // initialization or a call to LoadLibrary.

          case DLL_PROCESS_ATTACH:

            // Create a named file mapping object.

            hMapObject = CreateFileMapping(
                INVALID_HANDLE_VALUE, // use paging file
                NULL,                 // no security attributes
                PAGE_READWRITE,       // read/write access
                0,                    // size: high 32-bits
                SHMEMSIZE,            // size: low 32-bits
                "dllmemfilemap");     // name of map object
            if (hMapObject == NULL)
                return FALSE;

            // The first process to attach initializes memory.

            fInit = (GetLastError() != ERROR_ALREADY_EXISTS);

            // Get a pointer to the file-mapped shared memory.

            lpvMem = MapViewOfFile(
                hMapObject,     // object to map view of
                FILE_MAP_WRITE, // read/write access
                0,              // high offset:  map from
                0,              // low offset:   beginning
                0);             // default: map entire file
            if (lpvMem == NULL)
                return FALSE;

            // Initialize memory if this is the first process.

            if (fInit)
                memset(lpvMem, '\0', SHMEMSIZE);

            break;

        // The attached process creates a new thread.

        case DLL_THREAD_ATTACH:
            break;

        // The thread of the attached process terminates.

        case DLL_THREAD_DETACH:
            break;

        // The DLL is unloading from a process due to
        // process termination or a call to FreeLibrary.

        case DLL_PROCESS_DETACH:

            // Unmap shared memory from the process's address space.

            fIgnore = UnmapViewOfFile(lpvMem);

            // Close the process's handle to the file-mapping object.

            fIgnore = CloseHandle(hMapObject);

            break;

        default:
          break;
     }

    return TRUE;
    UNREFERENCED_PARAMETER(hinstDLL);
    UNREFERENCED_PARAMETER(lpvReserved);
}

// SetSharedMem sets the contents of shared memory.

VOID SetSharedMem(LPTSTR lpszBuf)
{
    LPTSTR lpszTmp;

    // Get the address of the shared memory block.

    lpszTmp = (LPTSTR) lpvMem;

    // Copy the null-terminated string into shared memory.

    while (*lpszBuf)
        *lpszTmp++ = *lpszBuf++;
    *lpszTmp = '\0';
}

// GetSharedMem gets the contents of shared memory.

VOID GetSharedMem(LPTSTR lpszBuf, DWORD cchSize)
{
    LPTSTR lpszTmp;

    // Get the address of the shared memory block.

    lpszTmp = (LPTSTR) lpvMem;

    // Copy from shared memory into the caller's buffer.

    while (*lpszTmp && --cchSize)
        *lpszBuf++ = *lpszTmp++;
    *lpszBuf = '\0';
}

Note that the shared memory can be mapped to a different address in each process. For this reason, each process has its own instance of the lpvMem parameter, which is declared as a global variable so that it is available to all DLL functions. The example assumes that the DLL global data is not shared, so each process that loads the DLL has its own instance of lpvMem.

In this example, the shared memory is released when the last handle to the file-mapping object is closed. To create persistent shared memory, a DLL can create a detached process (see CreateProcess) when the DLL is first loaded. If this detached process uses the DLL and does not terminate, it has a handle to the file-mapping object that prevents the shared memory from being released.


Using Thread Local Storage in a Dynamic-Link Library

This section shows the use of a DLL entry-point function to set up a thread local storage (TLS) index to provide private storage for each thread of a multithreaded process.

The entry-point function uses the TlsAlloc function to allocate a TLS index whenever a process loads the DLL. Each thread can then use this index to store a pointer to its own block of memory.

When the entry-point function is called with the DLL_PROCESS_ATTACH value, the code performs the following actions:

  1. Uses the TlsAlloc function to allocate a TLS index.
  2. Allocates a block of memory to be used exclusively by the initial thread of the process.
  3. Uses the TLS index in a call to the TlsSetValue function to store a pointer to the allocated memory.

Each time the process creates a new thread, the entry-point function is called with the DLL_THREAD_ATTACH value. The entry-point function then allocates a block of memory for the new thread and stores a pointer to it by using the TLS index. Each thread can use the TLS index in a call to TlsGetValue to retrieve the pointer to its own block of memory.

When a thread terminates, the entry-point function is called with the DLL_THREAD_DETACH value and the memory for that thread is freed. When a process terminates, the entry-point function is called with the DLL_PROCESS_DETACH value and the memory referenced by the pointer in the TLS index is freed.

The TLS index is stored in a global variable, making it available to all of the DLL functions. The following example assumes that the DLL's global data is not shared, because the TLS index is not necessarily the same for each process that loads the DLL.

static DWORD dwTlsIndex; // address of shared memory

// DllMain() is the entry-point function for this DLL.

BOOL DllMain(HINSTANCE hinstDLL,  // DLL module handle
    DWORD fdwReason,              // reason called
    LPVOID lpvReserved)           // reserved
{
    LPVOID lpvData;
    BOOL fIgnore;

    switch (fdwReason) {

        // The DLL is loading due to process
        // initialization or a call to LoadLibrary.

        case DLL_PROCESS_ATTACH:

            // Allocate a TLS index.

            if ((dwTlsIndex = TlsAlloc()) == 0xFFFFFFFF)
                return FALSE;

            // No break: Initialize the index for first thread.

        // The attached process creates a new thread.

        case DLL_THREAD_ATTACH:

            // Initialize the TLS index for this thread.

            lpvData = (LPVOID) LocalAlloc(LPTR, 256);
            if (lpvData != NULL)
                fIgnore = TlsSetValue(dwTlsIndex, lpvData);

            break;

        // The thread of the attached process terminates.

        case DLL_THREAD_DETACH:

            // Release the allocated memory for this thread.

            lpvData = TlsGetValue(dwTlsIndex);
            if (lpvData != NULL)
                LocalFree((HLOCAL) lpvData);

            break;

        // DLL unload due to process termination or FreeLibrary.

        case DLL_PROCESS_DETACH:

            // Release the allocated memory for this thread.

            lpvData = TlsGetValue(dwTlsIndex);
            if (lpvData != NULL)
                LocalFree((HLOCAL) lpvData);

            // Release the TLS index.

            TlsFree(dwTlsIndex);
            break;

        default:
            break;
    }

    return TRUE;
    UNREFERENCED_PARAMETER(hinstDLL);
    UNREFERENCED_PARAMETER(lpvReserved);
}

When a process uses load-time linking with this DLL, the entry-point function is sufficient to manage the thread local storage. Problems can occur with a process that uses run-time linking because the entry-point function is not called for threads that exist before the LoadLibrary function is called, so TLS memory is not allocated for these threads. The following example solves this problem by checking the value returned by the TlsGetValue function and allocating memory if the value indicates that the TLS slot for this thread is not set.

LPVOID lpvData;

// Retrieve a data pointer for the current thread.

lpvData = TlsGetValue(dwTlsIndex);

// If NULL, allocate memory for this thread.

if (lpvData == NULL) {
    lpvData = (LPVOID) LocalAlloc(LPTR, 256);
    if (lpvData != NULL)
        TlsSetValue(dwTlsIndex, lpvData);
}


Dynamic-Link Library Reference

The following elements are used in dynamic linking.

  • Dynamic-Link Library Functions


Dynamic-Link Library Functions

The following functions are used in dynamic linking.

Function | Description
DisableThreadLibraryCalls | Disables thread attach and thread detach notifications for the specified DLL.
DllMain | An optional entry point into a DLL.
FreeLibrary | Decrements the reference count of the loaded DLL. When the reference count reaches zero, the module is unmapped from the address space of the calling process.
FreeLibraryAndExitThread | Decrements the reference count of a loaded DLL by one, and then calls ExitThread to terminate the calling thread.
GetModuleFileName | Retrieves the full path and file name for the file containing the specified module.
GetModuleHandle | Retrieves a module handle for the specified module.
GetProcAddress | Retrieves the address of an exported function or variable from the specified DLL.
LoadLibrary | Maps the specified executable module into the address space of the calling process.
LoadLibraryEx | Maps the specified executable module into the address space of the calling process.

Obsolete Functions

These functions are provided only for compatibility with 16-bit versions of Windows.

LoadModule


DisableThreadLibraryCalls

The DisableThreadLibraryCalls function disables the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications for the specified dynamic-link library (DLL). This can reduce the size of the working code set for some applications.

BOOL DisableThreadLibraryCalls(
  HMODULE hModule  // handle to DLL module
);

Parameters

hModule
[in] Handle to the DLL module for which the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications are to be disabled. The LoadLibrary or GetModuleHandle function returns this handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. The DisableThreadLibraryCalls function fails if the DLL specified by hModule has active static thread local storage, or if hModule is an invalid module handle. To get extended error information, call GetLastError.

Remarks

The DisableThreadLibraryCalls function lets a DLL disable the DLL_THREAD_ATTACH and DLL_THREAD_DETACH notification calls. This can be a useful optimization for multithreaded applications that have many DLLs, frequently create and delete threads, and whose DLLs do not need these thread-level notifications of attachment/detachment. A remote procedure call (RPC) server application is an example of such an application. In these sorts of applications, DLL initialization routines often remain in memory to service DLL_THREAD_ATTACH and DLL_THREAD_DETACH notifications. By disabling the notifications, the DLL initialization code is not paged in because a thread is created or deleted, thus reducing the size of the application's working code set. To implement the optimization, modify a DLL's DLL_PROCESS_ATTACH code to call DisableThreadLibraryCalls.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, FreeLibraryAndExitThread


DllMain

The DllMain function is an optional entry point into a dynamic-link library (DLL). If the function is used, it is called by the system when processes and threads are initialized and terminated, or upon calls to the LoadLibrary and FreeLibrary functions.

DllMain is a placeholder for the library-defined function name. Earlier versions of the SDK documentation used DllEntryPoint as the entry-point function name. You must specify the actual name you use when you build your DLL. For more information, see the documentation included with your development tools.

BOOL WINAPI DllMain(
  HINSTANCE hinstDLL,  // handle to the DLL module
  DWORD fdwReason,     // reason for calling function
  LPVOID lpvReserved   // reserved
);

Parameters

hinstDLL
[in] Handle to the DLL module. The value is the base address of the DLL. The HINSTANCE of a DLL is the same as the HMODULE of the DLL, so hinstDLL can be used in calls to functions that require a module handle.
fdwReason
[in] Specifies a flag indicating why the DLL entry-point function is being called. This parameter can be one of the following values.
Value | Meaning
DLL_PROCESS_ATTACH | Indicates that the DLL is being loaded into the virtual address space of the current process as a result of the process starting up or as a result of a call to LoadLibrary. DLLs can use this opportunity to initialize any instance data or to use the TlsAlloc function to allocate a thread local storage (TLS) index.
DLL_THREAD_ATTACH Indicates that the current process is creating a new thread. When this occurs, the system calls the entry-point function of all DLLs currently attached to the process. The call is made in the context of the new thread. DLLs can use this opportunity to initialize a TLS slot for the thread. A thread calling the DLL entry-point function with DLL_PROCESS_ATTACH does not call the DLL entry-point function with DLL_THREAD_ATTACH.

Note that a DLL's entry-point function is called with this value only by threads created after the DLL is loaded by the process. When a DLL is loaded using LoadLibrary, existing threads do not call the entry-point function of the newly loaded DLL.
DLL_THREAD_DETACH | Indicates that a thread is exiting cleanly. If the DLL has stored a pointer to allocated memory in a TLS slot, it uses this opportunity to free the memory. The system calls the entry-point function of all currently loaded DLLs with this value. The call is made in the context of the exiting thread.
DLL_PROCESS_DETACH | Indicates that the DLL is being unloaded from the virtual address space of the calling process as a result of unsuccessfully loading the DLL, termination of the process, or a call to FreeLibrary. The DLL can use this opportunity to call the TlsFree function to free any TLS indices allocated by using TlsAlloc and to free any thread local data.

lpvReserved
[in] Specifies further aspects of DLL initialization and cleanup.

If fdwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.

If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary and non-NULL if DllMain has been called during process termination.

Return Values

When the system calls the DllMain function with the DLL_PROCESS_ATTACH value, the function returns TRUE if it succeeds or FALSE if initialization fails. If the return value is FALSE when DllMain is called because the process uses the LoadLibrary function, LoadLibrary returns NULL. (The system immediately calls your entry-point function with DLL_PROCESS_DETACH and unloads the DLL.) If the return value is FALSE when DllMain is called during process initialization, the process terminates with an error. To get extended error information, call GetLastError.

When the system calls the DllMain function with any value other than DLL_PROCESS_ATTACH, the return value is ignored.

Remarks

During initial process startup or after a call to LoadLibrary, the system scans the list of loaded DLLs for the process. For each DLL that has not already been called with the DLL_PROCESS_ATTACH value, the system calls the DLL's entry-point function. This call is made in the context of the thread that caused the process address space to change, such as the primary thread of the process or the thread that called LoadLibrary. Access to the entry point is serialized by the system on a process-wide basis.

There are cases in which the entry-point function is called for a terminating thread even if the DLL never attached to the thread — for example, the entry-point function was never called with the DLL_THREAD_ATTACH value in the context of the thread in either of these two situations:

  • The thread was the initial thread in the process, so the system called the entry-point function with the DLL_PROCESS_ATTACH value.
  • The thread was already running when a call to the LoadLibrary function was made, so the system never called the entry-point function for it.

When a DLL is unloaded from a process as a result of an unsuccessful load of the DLL, termination of the process, or a call to FreeLibrary, the system does not call the DLL's entry-point function with the DLL_THREAD_DETACH value for the individual threads of the process. The DLL is only sent a DLL_PROCESS_DETACH notification. DLLs can take this opportunity to clean up all resources for all threads known to the DLL.

Warning On attach, the body of your DLL entry-point function should perform only simple initialization tasks, such as setting up thread local storage (TLS), creating objects, and opening files. You must not call LoadLibrary in the entry-point function, because you may create dependency loops in the DLL load order. This can result in a DLL being used before the system has executed its initialization code. Similarly, you must not call the FreeLibrary function in the entry-point function on detach, because this can result in a DLL being used after the system has executed its termination code.

Calling Win32 functions other than TLS, object-creation, and file functions may result in problems that are difficult to diagnose. For example, calling User, Shell, COM, RPC, and Windows Sockets functions (or any functions that call these functions) can cause access violation errors, because their DLLs call LoadLibrary to load other system components. While it is acceptable to create synchronization objects in DllMain, you should not perform synchronization in DllMain (or a function called by DllMain) because all calls to DllMain are serialized. Waiting on synchronization objects in DllMain can cause a deadlock.

To provide more complex initialization, create an initialization routine for the DLL. You can require applications to call the initialization routine before calling any other routines in the DLL. Otherwise, you can have the initialization routine create a named mutex, and have each routine in the DLL call the initialization routine if the mutex does not exist.

For example, see Dynamic-Link Library Entry-Point Function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, Dynamic-Link Library Entry-Point Function, FreeLibrary, GetModuleFileName, LoadLibrary, TlsAlloc, TlsFree


FreeLibrary

The FreeLibrary function decrements the reference count of the loaded dynamic-link library (DLL). When the reference count reaches zero, the module is unmapped from the address space of the calling process and the handle is no longer valid.

BOOL FreeLibrary(
  HMODULE hModule   // handle to DLL module
);

Parameters

hModule
[in, out] Handle to the loaded DLL module. The LoadLibrary or GetModuleHandle function returns this handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Each process maintains a reference count for each loaded library module. This reference count is incremented each time LoadLibrary is called and is decremented each time FreeLibrary is called. A DLL module loaded at process initialization due to load-time dynamic linking has a reference count of one. This count is incremented if the same module is loaded by a call to LoadLibrary.

Before unmapping a library module, the system enables the DLL to detach from the process by calling the DLL's DllMain function, if it has one, with the DLL_PROCESS_DETACH value. Doing so gives the DLL an opportunity to clean up resources allocated on behalf of the current process. After the entry-point function returns, the library module is removed from the address space of the current process.

It is not safe to call FreeLibrary from DllMain. For more information, see the Remarks section in DllMain.

Calling FreeLibrary does not affect other processes using the same library module.

For example, see Using Run-Time Dynamic Linking.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, DllMain, FreeLibraryAndExitThread, GetModuleHandle, LoadLibrary


FreeLibraryAndExitThread

The FreeLibraryAndExitThread function decrements the reference count of a loaded dynamic-link library (DLL) by one, and then calls ExitThread to terminate the calling thread. The function does not return.

The FreeLibraryAndExitThread function gives threads that are created and executed within a dynamic-link library an opportunity to safely unload the DLL and terminate themselves.

VOID FreeLibraryAndExitThread(
  HMODULE hModule,  // handle to the DLL module
  DWORD dwExitCode  // exit code for thread
);

Parameters

hModule
[in] Handle to the DLL module whose reference count the function decrements. The LoadLibrary or GetModuleHandle function returns this handle.
dwExitCode
[in] Specifies the exit code for the calling thread.

Return Values

The function has no return value. The function does not return. Invalid hModule handles are ignored.

Remarks

The FreeLibraryAndExitThread function is implemented as:

FreeLibrary(hModule);
ExitThread(dwExitCode);

Refer to the reference pages for FreeLibrary and ExitThread for further information on those functions.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, FreeLibrary, ExitThread, DisableThreadLibraryCalls


GetModuleFileName

The GetModuleFileName function retrieves the full path and file name for the file containing the specified module.

Windows 95/98/Me: The GetModuleFilename function retrieves long file names when an application's version number is greater than or equal to 4.00 and the long file name is available. Otherwise, it returns only 8.3 format file names.

DWORD GetModuleFileName(
  HMODULE hModule,    // handle to module
  LPTSTR lpFilename,  // file name of module
  DWORD nSize         // size of buffer
);

Parameters

hModule
[in] Handle to the module whose file name is being requested. If this parameter is NULL, GetModuleFileName returns the path for the file containing the current process.
lpFilename
[out] Pointer to a buffer that receives the path and file name of the specified module.
nSize
[in] Specifies the length, in TCHARs, of the lpFilename buffer. If the length of the path and file name exceeds this limit, the string is truncated.

Return Values

If the function succeeds, the return value is the length, in TCHARs, of the string copied to the buffer.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If a DLL is loaded in two processes, its file name in one process may differ in case from its file name in the other process.

For the ANSI version of the function, the number of TCHARs is the number of bytes; for the Unicode version, it is the number of characters.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, GetModuleHandle, LoadLibrary


GetModuleHandle

The GetModuleHandle function retrieves a module handle for the specified module if the file has been mapped into the address space of the calling process.

HMODULE GetModuleHandle(
  LPCTSTR lpModuleName   // module name
);

Parameters

lpModuleName
[in] Pointer to a null-terminated string that contains the name of the module (either a .dll or .exe file). If the file name extension is omitted, the default library extension .dll is appended. The file name string can include a trailing point character (.) to indicate that the module name has no extension. The string does not have to specify a path. When specifying a path, be sure to use backslashes (\), not forward slashes (/). The name is compared (case independently) to the names of modules currently mapped into the address space of the calling process.

If this parameter is NULL, GetModuleHandle returns a handle to the file used to create the calling process.

Return Values

If the function succeeds, the return value is a handle to the specified module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The returned handle is not global, inheritable, or duplicative, and it cannot be used by another process.

The handles returned by GetModuleHandle and LoadLibrary can be used in the same functions — for example, GetProcAddress, FreeLibrary, or LoadResource. The difference between the two functions involves the reference count. LoadLibrary maps the module into the address space of the calling process, if necessary, and increments the module's reference count, if it is already mapped. GetModuleHandle, however, returns the handle to a mapped module without incrementing its reference count.

Note that the reference count is used in FreeLibrary to determine whether to unmap the function from the address space of the process. For this reason, use care when using a handle returned by GetModuleHandle in a call to FreeLibrary because doing so can cause a dynamic-link library (DLL) module to be unmapped prematurely.

This function must also be used carefully in a multithreaded application. There is no guarantee that the module handle remains valid between the time this function returns the handle and the time it is used by another function. For example, a thread might retrieve a module handle by calling GetModuleHandle. Before the thread uses the handle in another function, a second thread could free the module and the system could load another module, giving it the same handle as the module that was recently freed. The first thread would then be left with a module handle that refers to a module different than the one intended.

For example, see Using Brushes.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, FreeLibrary, GetModuleFileName, GetProcAddress, LoadLibrary, LoadResource


GetProcAddress

The GetProcAddress function retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).

FARPROC GetProcAddress(
  HMODULE hModule,    // handle to DLL module
  LPCSTR lpProcName   // function name
);

Parameters

hModule
[in] Handle to the DLL module that contains the function or variable. The LoadLibrary or GetModuleHandle function returns this handle.
lpProcName
[in] Pointer to a null-terminated string containing the function or variable name, or the function's ordinal value. If this parameter is an ordinal value, it must be in the low-order word; the high-order word must be zero.

Return Values

If the function succeeds, the return value is the address of the exported function or variable.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The spelling and case of a function name pointed to by lpProcName must be identical to that in the EXPORTS statement of the source DLL's module-definition (.Def) file. The exported names of functions may differ from the names you use when calling these functions in your code. This difference is hidden by macros used in the SDK header files. For more information, see Win32 Function Prototypes.

The lpProcName parameter can identify the DLL function by specifying an ordinal value associated with the function in the EXPORTS statement. GetProcAddress verifies that the specified ordinal is in the range 1 through the highest ordinal value exported in the .DEF file. The function then uses the ordinal as an index to read the function's address from a function table. If the .DEF file does not number the functions consecutively from 1 to N (where N is the number of exported functions), an error can occur where GetProcAddress returns an invalid, non-NULL address, even though there is no function with the specified ordinal.

In cases where the function may not exist, the function should be specified by name rather than by ordinal value.

For an example, see Using Run-Time Dynamic Linking.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, FreeLibrary, GetModuleHandle, LoadLibrary


LoadLibrary

The LoadLibrary function maps the specified executable module into the address space of the calling process.

For additional load options, use the LoadLibraryEx function.

HMODULE LoadLibrary(
  LPCTSTR lpFileName   // file name of module
);

Parameters

lpFileName
[in] Pointer to a null-terminated string that names the executable module (either a .dll or .exe file). The name specified is the file name of the module and is not related to the name stored in the library module itself, as specified by the LIBRARY keyword in the module-definition (.def) file.

If the string specifies a path but the file does not exist in the specified directory, the function fails. When specifying a path, be sure to use backslashes (\), not forward slashes (/).

If the string does not specify a path, the function uses a standard search strategy to find the file. See the Remarks for more information.

Return Values

If the function succeeds, the return value is a handle to the module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Windows 95/98/Me: If you are using LoadLibrary to load a module that contains a resource whose numeric identifier is greater than 0x7FFF, LoadLibrary fails. If you are attempting to load a 16-bit DLL directly from 32-bit code, LoadLibrary fails. If you are attempting to load a DLL whose subsystem version is greater than 4.0, LoadLibrary fails. If your DllMain function tries to call the Unicode version of a Win32 function, LoadLibrary fails.

Remarks

LoadLibrary can be used to map a DLL module and return a handle that can be used in GetProcAddress to get the address of a DLL function. LoadLibrary can also be used to map other executable modules. For example, the function can specify an .exe file to get a handle that can be used in FindResource or LoadResource. However, do not use LoadLibrary to run an .exe file, use the CreateProcess function.

If the module is a DLL not already mapped for the calling process, the system calls the DLL's DllMain function with the DLL_PROCESS_ATTACH value. If the DLL's entry-point function does not return TRUE, LoadLibrary fails and returns NULL. (The system immediately calls your entry-point function with DLL_PROCESS_DETACH and unloads the DLL.)

It is not safe to call LoadLibrary from DllMain. For more information, see the Remarks section in DllMain.

Module handles are not global or inheritable. A call to LoadLibrary by one process does not produce a handle that another process can use — for example, in calling GetProcAddress. The other process must make its own call to LoadLibrary for the module before calling GetProcAddress.

If no file name extension is specified in the lpFileName parameter, the default library extension .dll is appended. However, the file name string can include a trailing point character (.) to indicate that the module name has no extension. When no path is specified, the function searches for loaded modules whose base name matches the base name of the module to be loaded. If the name matches, the load succeeds. Otherwise, the function searches for the file in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory.
  3. Windows 95/98/Me: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

    Windows NT/2000 or later: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

  4. Windows NT/2000 or later: The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

The first directory searched is the one directory containing the image file used to create the calling process (for more information, see the CreateProcess function). Doing this allows private dynamic-link library (DLL) files associated with a process to be found without adding the process's installed directory to the PATH environment variable.

Windows 2000 or later: If a path is specified and there is a redirection file for the application, the function searches for the module in the application's directory. If the module exists in the application's directory, the LoadLibrary function ignores the specified path and loads the module from the application's directory. If the module does not exist in the application's directory, LoadLibrary loads the module from the specified directory.

The Visual C++ compiler supports a syntax that enables you to declare thread-local variables: _declspec(thread). If you use this syntax in a DLL, you will not be able to load the DLL explicitly using LoadLibrary or LoadLibraryEx. If your DLL will be loaded explicitly, you must use the thread local storage functions instead of _declspec(thread).

For example, see Using Run-Time Dynamic Linking.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, DllMain, FindResource, FreeLibrary, GetProcAddress, GetSystemDirectory, GetWindowsDirectory, LoadLibraryEx, LoadResource


LoadLibraryEx

The LoadLibraryEx function maps the specified executable module into the address space of the calling process. The executable module can be a .dll or an .exe file. The specified module may cause other modules to be mapped into the address space.

HMODULE LoadLibraryEx(
  LPCTSTR lpFileName,  // file name of module
  HANDLE hFile,           // reserved, must be NULL
  DWORD dwFlags           // entry-point execution option
);

Parameters

lpFileName
[in] Pointer to a null-terminated string that names the executable module (either a .dll or an .exe file). The name specified is the file name of the executable module. This name is not related to the name stored in a library module itself, as specified by the LIBRARY keyword in the module-definition (.DEF) file.

If the string specifies a path, but the file does not exist in the specified directory, the function fails. When specifying a path, be sure to use backslashes (\), not forward slashes (/).

If the string does not specify a path, and the file name extension is omitted, the function appends the default library extension .dll to the file name. However, the file name string can include a trailing point character (.) to indicate that the module name has no extension.

If the string does not specify a path, the function uses a standard search strategy to find the file. See the Remarks for more information.

If mapping the specified module into the address space causes the system to map in other, associated executable modules, the function can use either the standard search strategy or an alternate search strategy to find those modules. See the Remarks for more information.

hFile
This parameter is reserved for future use. It must be NULL.
dwFlags
[in] Specifies the action to take when loading the module. If no flags are specified, the behavior of this function is identical to that of the LoadLibrary function. This parameter can be one of the following values.
Flag | Meaning
DONT_RESOLVE_DLL_REFERENCES Windows NT/2000 or later: If this value is used, and the executable module is a DLL, the system does not call DllMain for process and thread initialization and termination. Also, the system does not load additional executable modules that are referenced by the specified module.

If this value is not used, and the executable module is a DLL, the system calls DllMain for process and thread initialization and termination. The system loads additional executable modules that are referenced by the specified module.

LOAD_IGNORE_CODE_AUTHZ_LEVEL | Whistler: If this value is used, the system does not perform automatic trust comparisons on the DLL or its dependents when they are loaded.
LOAD_LIBRARY_AS_DATAFILE If this value is used, the system maps the file into the calling process's virtual address space as if it were a data file. Nothing is done to execute or prepare to execute the mapped file. Use this flag when you want to load a DLL only to extract messages or resources from it.

Windows NT/2000 or later: You can use the resulting module handle with any Win32 functions that operate on resources.

Windows 95/98/Me: You can use the resulting module handle only with resource management functions such as EnumResourceLanguages, EnumResourceNames, EnumResourceTypes, FindResource, FindResourceEx, LoadResource, and SizeofResource. You cannot use this handle with specialized resource management functions such as LoadBitmap, LoadCursor, LoadIcon, LoadImage, and LoadMenu.

LOAD_WITH_ALTERED_SEARCH_PATH If this value is used, and lpFileName specifies a path, the system uses the alternate file search strategy discussed in the Remarks section to find associated executable modules that the specified module causes to be loaded.

If this value is not used, or if lpFileName does not specify a path, the system uses the standard search strategy discussed in the Remarks section to find associated executable modules that the specified module causes to be loaded.

Return Values

If the function succeeds, the return value is a handle to the mapped executable module.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Windows 95/98/Me: If you are using LoadLibraryEx to load a module that contains a resource whose numeric identifier is greater than 0x7FFF, LoadLibraryEx fails. If you are attempting to load a 16-bit DLL directly from 32-bit code, LoadLibraryEx fails. If you are attempting to load a DLL whose subsystem version is greater than 4.0, LoadLibraryEx fails. If your DllMain function tries to call the Unicode version of a Win32 function, LoadLibraryEx fails.

Remarks

The calling process can use the handle returned by this function to identify the module in calls to the GetProcAddress, FindResource, and LoadResource functions.

The LoadLibraryEx function is very similar to the LoadLibrary function. The differences consist of a set of optional behaviors that LoadLibraryEx provides. First, LoadLibraryEx can map a DLL module without calling the DllMain function of the DLL. Second, LoadLibraryEx can use either of two file search strategies to find executable modules that are associated with the specified module. Third, LoadLibraryEx can load a module in a way that is optimized for the case where the module will never be executed, loading the module as if it were a data file. You select these optional behaviors by setting the dwFlags parameter; if dwFlags is zero, LoadLibraryEx behaves identically to LoadLibrary.

It is not safe to call LoadLibraryEx from DllMain. For more information, see the Remarks section in DllMain.

If no path is specified in the lpFileName parameter, and the base file name does not match the base file name of a loaded module, the LoadLibraryEx function uses the same standard file search strategy that LoadLibrary, SearchPath, and OpenFile use to find the executable module and any associated executable modules that it causes to be loaded. This standard strategy searches for a file in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory.
  3. Windows 95/98/Me: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

    Windows NT/2000 or later: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

  4. Windows NT/2000 or later: The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

If a path is specified, and the dwFlags parameter is set to LOAD_WITH_ALTERED_SEARCH_PATH, the LoadLibraryEx function uses an alternate file search strategy to find any executable modules that the specified module causes to be loaded. This alternate strategy searches for a file in the following sequence:

  1. The directory specified by the lpFileName path. In other words, the directory that the specified executable module is in.
  2. The current directory.
  3. Windows 95/98/Me: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

    Windows NT/2000 or later: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

  4. Windows NT/2000 or later: The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.

Note that the standard file search strategy and the alternate search strategy differ in just one way: the standard strategy starts its search in the calling application's directory, and the alternate strategy starts its search in the directory of the executable module that LoadLibraryEx is loading.

If you specify the alternate search strategy, its behavior continues until all associated executable modules have been located. After the system starts processing DLL initialization routines, the system reverts to the standard search strategy.

Windows 2000 or later: If a path is specified and there is a redirection file associated with the application, the LoadLibraryEx function searches for the module in the application directory. If the module exists in the application directory, LoadLibraryEx ignores the path specification and loads the module from the application directory. If the module does not exist in the application directory, the function loads the module from the specified directory.

Visual C++: The Visual C++ compiler supports a syntax that enables you to declare thread-local variables: _declspec(thread). If you use this syntax in a DLL, you will not be able to load the DLL explicitly using LoadLibrary or LoadLibraryEx. If your DLL will be loaded explicitly, you must use the thread local storage functions instead of _declspec(thread).

For example, see Looking Up Text for Error Code Numbers.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, DllMain, FindResource, FreeLibrary, GetProcAddress, GetSystemDirectory, GetWindowsDirectory, LoadLibrary, LoadResource, OpenFile, SearchPath


LoadModule

The LoadModule function loads and executes an application or creates a new instance of an existing application.

Note This function is provided only for compatibility with 16-bit versions of Windows. Win32-based applications should use the CreateProcess function.

DWORD LoadModule(
  LPCSTR lpModuleName,      // file name of application
  LPVOID lpParameterBlock   // parameter block
);

Parameters

lpModuleName
[in] Pointer to a null-terminated string that contains the file name of the application to run. When specifying a path, be sure to use backslashes (\), not forward slashes (/). If the lpModuleName parameter does not contain a directory path, the system searches for the executable file in this order:
  1. The directory from which the application loaded.
  2. The current directory.
  3. Windows 95/98/Me: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

    Windows NT/2000 or later: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is SYSTEM32.

  4. Windows NT/2000 or later: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is SYSTEM.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.
lpParameterBlock
[in] Pointer to an application-defined LOADPARMS32 structure that defines the new application's parameter block.

The LOADPARMS32 structure has the following form:

typedef struct tagLOADPARMS32 {
    LPSTR lpEnvAddress;  // address of environment strings
    LPSTR lpCmdLine;     // address of command line
    LPSTR lpCmdShow;     // how to show new program
    DWORD dwReserved;    // must be zero
} LOADPARMS32;
Member | Description
lpEnvAddress | Pointer to an array of null-terminated strings that supply the environment strings for the new process. The array has a value of NULL as its last entry. A value of NULL for this parameter causes the new process to start with the same environment as the calling process.
lpCmdLine | Pointer to a Pascal-style string that contains a correctly formed command line. The first byte of the string contains the number of bytes in the string. The remainder of the string contains the command line arguments, excluding the name of the child process. If there are no command line arguments, this parameter must point to a zero length string; it cannot be NULL.
lpCmdShow | Pointer to a structure containing two WORD values. The first value must always be set to two. The second value specifies how the application window is to be shown and is used to supply the wShowWindow member of the STARTUPINFO structure to the CreateProcess function. See the description of the nCmdShow parameter of the ShowWindow function for a list of acceptable values.
dwReserved | This parameter is reserved; it must be zero.

Set all unused members to NULL, except for lpCmdLine, which must point to a null-terminated string if it is not used.

Return Values

If the function succeeds, the return value is greater than 31.

If the function fails, the return value is an error value, which may be one of the following values.

Value | Meaning
0 | The system is out of memory or resources.
ERROR_BAD_FORMAT | The .exe file is invalid (non-Win32 .exe or error in .exe image).
ERROR_FILE_NOT_FOUND | The specified file was not found.
ERROR_PATH_NOT_FOUND | The specified path was not found.

Remarks

Applications should use the CreateProcess function instead of LoadModule. The LoadModule function calls CreateProcess. by forming the parameters as follows.

CreateProcess parameter | Value
lpszApplicationName | lpModuleName
lpszCommandLine | lpParameterBlock->lpCmdLine
lpProcessAttributes | NULL
lpThreadAttributes | NULL
bInheritHandles | FALSE
dwCreationFlags | 0
lpEnvironment | lpParameterBlock->lpEnvAddress
lpCurrentDirectory | NULL
lpStartupInfo | The structure is initialized to zero. The cb member is set to the size of the structure, and the wShowWindow member is set to the value of the second word of the LoadModule lpParameterBlock->lpCmdShow parameter.
lpProcessInformation.hProcess | The handle is immediately closed.
lpProcessInformation.hThread | The handle is immediately closed.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Dynamic-Link Libraries Overview, Dynamic-Link Library Functions, CreateProcess, GetSystemDirectory, GetWindowsDirectory, ShowWindow, STARTUPINFO, WinExec


Processes and Threads

A Win32®-based application consists of one or more processes. A process, in the simplest terms, is an executing program. One or more threads run in the context of the process. A thread is the basic unit to which the operating system allocates processor time. A thread can execute any part of the process code, including parts currently being executed by another thread. A fiber is a unit of execution that must be manually scheduled by the application. Fibers run in the context of the threads that schedule them.

A job object allows groups of processes to be managed as a unit. Job objects are namable, securable, sharable objects that control attributes of the processes associated with them. Operations performed on the job object affect all processes associated with the job object.

  • About Processes and Threads
  • Using Processes and Threads
  • Process and Thread Reference


About Processes and Threads

Each process provides the resources needed to execute a program. A process has a virtual address space, executable code, data, object handles, environment variables, a base priority, and minimum and maximum working set sizes. Each process is started with a single thread, often called the primary thread, but can create additional threads from any of its threads.

All threads of a process share its virtual address space and system resources. In addition, each thread maintains exception handlers, a scheduling priority, and a set of structures the system will use to save the thread context until it is scheduled. The thread context includes the thread's set of machine registers, the kernel stack, a thread environment block, and a user stack in the address space of the thread's process.

Windows NT/2000 and Windows 95/98 support preemptive multitasking, which creates the effect of simultaneous execution of multiple threads from multiple processes. On a multiprocessor computer, Windows NT/2000 can simultaneously execute as many threads as there are processors on the computer.

This overview discusses the following topics:

  • Multitasking
  • Scheduling
  • Multiple Threads
  • Child Processes
  • Process Working Set
  • Thread Pooling
  • Job Objects
  • Fibers


Multitasking

A multitasking operating system divides the available processor time among the processes or threads that need it. The system is designed for preemptive multitasking; it allocates a processor time slice to each thread it executes. The currently executing thread is suspended when its time slice elapses, allowing another thread to run. When the system switches from one thread to another, it saves the context of the preempted thread and restores the saved context of the next thread in the queue.

The length of the time slice depends on the operating system and the processor. Because each time slice is small (approximately 20 milliseconds), multiple threads appear to be executing at the same time. This is actually the case on multiprocessor systems, where the executable threads are distributed among the available processors. However, you must use caution when using multiple threads in an application, because system performance can decrease if there are too many threads.


Advantages of Multitasking

To the user, the advantage of multitasking is the ability to have several applications open and working at the same time. For example, a user can edit a file with one application while another application is recalculating a spreadsheet.

To the application developer, the advantage of multitasking is the ability to create applications that use more than one process and to create processes that use more than one thread of execution. For example, a process can have a user interface thread that manages interactions with the user (keyboard and mouse input), and worker threads that perform other tasks while the user interface thread waits for user input. If you give the user interface thread a higher priority, the application will be more responsive to the user, while the worker threads use the processor efficiently during the times when there is no user input.


When to Use Multitasking

There are two ways to implement multitasking: as a single process with multiple threads or as multiple processes, each with one or more threads. An application can put each thread that requires a private address space and private resources into its own process, to protect it from the activities of other process threads.

A multithreaded process can manage mutually exclusive tasks with threads, such as providing a user interface and performing background calculations. Creating a multithreaded process can also be a convenient way to structure a program that performs several similar or identical tasks concurrently. For example, a named pipe server can create a thread for each client process that attaches to the pipe. This thread manages the communication between the server and the client. Your process could use multiple threads to accomplish the following tasks:

  • Manage input for multiple windows.
  • Manage input from several communications devices.
  • Distinguish tasks of varying priority. For example, a high-priority thread manages time-critical tasks, and a low-priority thread performs other tasks.
  • Allow the user interface to remain responsive, while allocating time to background tasks.

It is typically more efficient for an application to implement multitasking by creating a single, multithreaded process, rather than creating multiple processes, for the following reasons:

  • The system can perform a context switch more quickly for threads than processes, because a process has more overhead than a thread does (the process context is larger than the thread context).
  • All threads of a process share the same address space and can access the process's global variables, which can simplify communication between threads.
  • All threads of a process can share open handles to resources, such as files and pipes.

The Win32 API also provides alternative methods that can be used in the place of multithreading. The most significant of these methods are asynchronous input and output (I/O), I/O completion ports, asynchronous procedure calls (APC), and the ability to wait for multiple events.

A single thread can initiate multiple time-consuming I/O requests that can run concurrently using asynchronous I/O. Asynchronous I/O can be performed on files, pipes, and serial communication devices. For more information, see Synchronization and Overlapped Input and Output.

A single thread can block its own execution while waiting for any one or all of several events to occur. This is more efficient than using multiple threads, each waiting for a single event, and more efficient than using a single thread that consumes processor time by continually checking for events to occur. For more information, see Wait Functions.


Multitasking Considerations

The recommended guideline is to use as few threads as possible, thereby minimizing the use of system resources. This improves performance. Multitasking has resource requirements and potential conflicts to be considered when designing your application. The resource requirements are as follows:

  • The system consumes memory for the context information required by both processes and threads. Therefore, the number of processes and threads that can be created is limited by available memory.
  • Keeping track of a large number of threads consumes significant processor time. If there are too many threads, most of them will not be able to make significant progress. If most of the current threads are in one process, threads in other processes are scheduled less frequently.

Providing shared access to resources can create conflicts. To avoid them, you must synchronize access to shared resources. This is true for system resources (such as communications ports), resources shared by multiple processes (such as file handles), or the resources of a single process (such as global variables) accessed by multiple threads. Failure to synchronize access properly (in the same or in different processes) can lead to problems such as deadlock and race conditions. The Win32 API provides a set of synchronization objects and functions you can use to coordinate resource sharing among multiple threads. For more information about synchronization, see Synchronizing Execution of Multiple Threads. Reducing the number of threads makes it easier and more effective to synchronize resources.

A good design for a multithreaded application is the pipeline server. In this design, you create one thread per processor and build queues of requests for which the application maintains the context information. A thread would process all requests in a queue before processing requests in the next queue.


Scheduling

The system scheduler controls multitasking by determining which of the competing threads receives the next processor time slice. The scheduler determines which thread runs next using its scheduling priority.

This section discusses the following topics:

  • Scheduling Priorities
  • Context Switches
  • Priority Boosts
  • Priority Inversion
  • Multiple Processors


Scheduling Priorities

Each thread is assigned a scheduling priority. The priority levels range from zero (lowest priority) to 31 (highest priority). Only the zero-page thread can have a priority of zero. The zero-page thread is a system thread.

The priority of each thread is determined by the following criteria:

  • The priority class of its process
  • The priority level of the thread within the priority class of its process

The priority class and priority level are combined to form the base priority of a thread.

Priority Class

Each process belongs to one of the following priority classes:

IDLE_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS
ABOVE_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS

Windows 2000 and later: Note that BELOW_NORMAL_PRIORITY_CLASS and ABOVE_NORMAL_PRIORITY_CLASS are new for Windows 2000.

By default, the priority class of a process is NORMAL_PRIORITY_CLASS. Use the CreateProcess function to specify the priority class of a child process when you create it. If the calling process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS, the new process will inherit this class. Use the GetPriorityClass function to determine the current priority class of a process and the SetPriorityClass function to change the priority class of a process.

Processes that monitor the system, such as screen savers or applications that periodically update a display, should use IDLE_PRIORITY_CLASS. This prevents the threads of this process, which do not have high priority, from interfering with higher priority threads.

Use HIGH_PRIORITY_CLASS with care. If a thread runs at the highest priority level for extended periods, other threads in the system will not get processor time. If several threads are set at high priority at the same time, the threads lose their effectiveness. The high-priority class should be reserved for threads that must respond to time-critical events. If your application performs one task that requires the high-priority class while the rest of its tasks are normal priority, use SetPriorityClass to raise the priority class of the application temporarily; then reduce it after the time-critical task has been completed. Another strategy is to create a high-priority process that has all of its threads blocked most of the time, awakening threads only when critical tasks are needed. The important point is that a high-priority thread should execute for a brief time, and only when it has time-critical work to perform.

You should almost never use REALTIME_PRIORITY_CLASS, because this interrupts system threads that manage mouse input, keyboard input, and background disk flushing. This class can be appropriate for applications that "talk" directly to hardware or that perform brief tasks that should have limited interruptions.

Priority Level

The following are priority levels within each priority class

THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST
THREAD_PRIORITY_BELOW_NORMAL
THREAD_PRIORITY_NORMAL
THREAD_PRIORITY_ABOVE_NORMAL
THREAD_PRIORITY_HIGHEST
THREAD_PRIORITY_TIME_CRITICAL

All threads are created using THREAD_PRIORITY_NORMAL. This means that the thread priority is the same as the process priority class. After you create a thread, use the SetThreadPriority function to adjust its priority relative to other threads in the process.

A typical strategy is to use THREAD_PRIORITY_ABOVE_NORMAL or THREAD_PRIORITY_HIGHEST for the process's input thread, to ensure that the application is responsive to the user. Background threads, particularly those that are processor intensive, can be set to THREAD_PRIORITY_BELOW_NORMAL or THREAD_PRIORITY_LOWEST, to ensure that they can be preempted when necessary. However, if you have a thread waiting for another thread with a lower priority to complete some task, be sure to block the execution of the waiting high-priority thread. To do this, use a wait function, critical section, or the Sleep function, SleepEx, or SwitchToThread function. This is preferable to having the thread execute a loop. Otherwise, the process may become deadlocked, because the thread with lower priority is never scheduled.

To determine the current priority level of a thread, use the GetThreadPriority function.

Base Priority

The priority level of a thread is determined by both the priority class of its process and its priority level. The priority class and priority level are combined to form the base priority of each thread.

The following table shows the base priority levels for combinations of priority class and priority value.

 | Process Priority Class | Thread Priority Level
1 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_IDLE
1 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_IDLE
1 | NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_IDLE
1 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_IDLE
1 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_IDLE
2 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
3 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
4 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
4 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
5 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
5 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
5 | Background NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
6 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
6 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
6 | Background NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
7 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
7 | Background NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
7 | Foreground NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
8 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
8 | NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
8 | Foreground NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
8 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
9 | NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
9 | Foreground NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
9 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
10 | Foreground NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
10 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
11 | Foreground NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
11 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
11 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
12 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
12 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
13 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
14 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
15 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
15 | HIGH_PRIORITY_CLASS | THREAD_PRIORITY_TIME_CRITICAL
15 | IDLE_PRIORITY_CLASS | THREAD_PRIORITY_TIME_CRITICAL
15 | BELOW_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_TIME_CRITICAL
15 | NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_TIME_CRITICAL
15 | ABOVE_NORMAL_PRIORITY_CLASS | THREAD_PRIORITY_TIME_CRITICAL
16 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_IDLE
17 | REALTIME_PRIORITY_CLASS | -7
18 | REALTIME_PRIORITY_CLASS | -6
19 | REALTIME_PRIORITY_CLASS | -5
20 | REALTIME_PRIORITY_CLASS | -4
21 | REALTIME_PRIORITY_CLASS | -3
22 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_LOWEST
23 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_BELOW_NORMAL
24 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_NORMAL
25 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_ABOVE_NORMAL
26 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_HIGHEST
27 | REALTIME_PRIORITY_CLASS | 3
28 | REALTIME_PRIORITY_CLASS | 4
29 | REALTIME_PRIORITY_CLASS | 5
30 | REALTIME_PRIORITY_CLASS | 6
31 | REALTIME_PRIORITY_CLASS | THREAD_PRIORITY_TIME_CRITICAL

Windows 2000 and later: Note that the values -7, -6, -5, -4, -3, 3, 4, 5, and 6 are supported only on Windows 2000 and later.


Context Switches

The scheduler maintains a queue of executable threads for each priority level. These are known as ready threads. When a processor becomes available, the system performs a context switch. The steps in a context switch are:

  1. Save the context of the thread that just finished executing.
  2. Place the thread that just finished executing at the end of the queue for its priority.
  3. Find the highest priority queue that contains ready threads.
  4. Remove the thread at the head of the queue, load its context, and execute it.

The following classes of threads are not ready threads.

  • Threads created with the CREATE_SUSPENDED flag
  • Threads halted during execution with the SuspendThread or SwitchToThread function
  • Threads waiting for a synchronization object or input.

Until threads that are suspended or blocked become ready to run, the scheduler does not allocate any processor time to them, regardless of their priority.

The most common reasons for a context switch are:

  • The time slice has elapsed.
  • A thread with a higher priority has become ready to run.
  • A running thread needs to wait.

When a running thread needs to wait, it relinquishes the remainder of its time slice.


Priority Boosts

Each thread has a dynamic priority. This is the priority the scheduler uses to determine which thread to execute. Initially, a thread's dynamic priority is the same as its base priority. The system can boost and lower the dynamic priority, to ensure that it is responsive and that no threads are starved for processor time. The system does not boost the priority of threads with a base priority level between 16 and 31. Only threads with a base priority between 0 and 15 receive dynamic priority boosts.

The system boosts the dynamic priority of a thread to enhance its responsiveness as follows.

  • When a process that uses NORMAL_PRIORITY_CLASS is brought to the foreground, the scheduler boosts the priority class of the process associated with the foreground window, so that it is greater than or equal to the priority class of any background processes. The priority class returns to its original setting when the process is no longer in the foreground.

    Windows NT/2000 or later: The user can control the boosting of processes that use NORMAL_PRIORITY_CLASS through the System control panel application.

  • When a window receives input, such as timer messages, mouse messages, or keyboard input, the scheduler boosts the priority of the thread that owns the window.
  • When the wait conditions for a blocked thread are satisfied, the scheduler boosts the priority of the thread. For example, when a wait operation associated with disk or keyboard I/O finishes, the thread receives a priority boost.

    Windows NT/2000 or later: You can disable the priority-boosting feature by calling the SetProcessPriorityBoost or SetThreadPriorityBoost function. To determine whether this feature has been disabled, call the GetProcessPriorityBoost or GetThreadPriorityBoost function.

After raising a thread's dynamic priority, the scheduler reduces that priority by one level each time the thread completes a time slice, until the thread drops back to its base priority. A thread's dynamic priority is never less than its base priority.


Priority Inversion

Priority inversion occurs when two or more threads with different priorities are in contention to be scheduled. Consider a simple case with three threads: thread 1, thread 2, and thread 3. Thread 1 is high priority and becomes ready to be scheduled. Thread 2, a low-priority thread, is executing code in a critical section. Thread 1, the high-priority thread, begins waiting for a shared resource from thread 2. Thread 3 has medium priority. Thread 3 receives all the processor time, because the high-priority thread (thread 1) is waiting for shared resources from the low-priority thread (thread 2). Thread 2 won't leave the critical section, because does not have the highest priority and won't be scheduled.

  • Windows NT/2000 or later: The scheduler solves this problem by randomly boosting the priority of the ready threads (in this case, the low priority lock-holders). The low priority threads run long enough to exit the critical section, and the high- priority thread can enter the critical section. If the low-priority thread doesn't get enough CPU time to exit the critical section the first time, it will get another chance during the next round of scheduling.
  • Windows 95/98/Me: If a high-priority thread is dependent on a low-priority thread that will not be allowed to run because a medium priority thread is getting all of the CPU time, the system recognizes that the high-priority thread is dependent on the low-priority thread. It will boost the low-priority thread's priority up to the priority of the high-priority thread. This will allow the thread that formerly had the lowest priority to run and release the high-priority thread that was waiting for it.


Multiple Processors

Windows NT uses a symmetric multiprocessing (SMP) model to schedule threads on multiple processors. With this model, any thread can be assigned to any processor. Therefore, scheduling threads on a computer with multiple processors is similar to scheduling threads on a computer with a single processor. However, the scheduler has a pool of processors, so that it can schedule threads to run concurrently. Scheduling is still determined by thread priority. However, on a multiprocessor computer, you can also affect scheduling by setting thread affinity and thread ideal processor, as discussed here.

Thread Affinity

Thread affinity forces a thread to run on a specific subset of processors. Use the SetProcessAffinityMask function to specify thread affinity for all threads of the process. To set the thread affinity for a single thread, use the SetThreadAffinityMask function. The thread affinity must be a subset of the process affinity. You can obtain the current process affinity by calling the GetProcessAffinityMask function.

Setting thread affinity should generally be avoided, because it can interfere with the scheduler's ability to schedule threads effectively across processors. This can decrease the performance gains produced by parallel processing. An appropriate use of thread affinity is testing each processor.

Thread Ideal Processor

When you specify a thread ideal processor, the scheduler runs the thread on the specified processor when possible. Use the SetThreadIdealProcessor function to specify a preferred processor for a thread. This does not guarantee that the ideal processor will be chosen, but provides a useful hint to the scheduler.


Multiple Threads

Each process is started with a single thread, but can create additional threads from any of its threads.

This section discusses the following topics:

  • Creating Threads
  • Thread Stack Size
  • Thread Handles and Identifiers
  • Suspending Thread Execution
  • Synchronizing Execution of Multiple Threads
  • Multiple Threads and GDI Objects
  • Thread Local Storage
  • Creating Windows in Threads
  • Terminating a Thread
  • Thread Times
  • Thread Security and Access Rights


Creating Threads

The CreateThread function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program code. This function takes a single parameter and returns a DWORD value. A process can have multiple threads simultaneously executing the same function.

The following example demonstrates how to create a new thread that executes the locally defined function, ThreadFunc.

#include <windows.h>
#include <conio.h>

DWORD WINAPI ThreadFunc( LPVOID lpParam )
{
    char szMsg[80];

    wsprintf( szMsg, "Parameter = %d.", *(DWORD*)lpParam );
    MessageBox( NULL, szMsg, "ThreadFunc", MB_OK );

    return 0;
}

VOID main( VOID )
{
    DWORD dwThreadId, dwThrdParam = 1;
    HANDLE hThread;
    char szMsg[80];

    hThread = CreateThread(
        NULL,                        // no security attributes
        0,                           // use default stack size
        ThreadFunc,                  // thread function
        &dwThrdParam,                // argument to thread function
        0,                           // use default creation flags
        &dwThreadId);                // returns the thread identifier

   // Check the return value for success.

   if (hThread == NULL)
   {
      wsprintf( szMsg, "CreateThread failed." );
      MessageBox( NULL, szMsg, "main", MB_OK );
   }
   else
   {
      _getch();
      CloseHandle( hThread );
   }
}

For simplicity, this example passes a pointer to a DWORD value as an argument to the thread function. This could be a pointer to any type of data or structure, or it could be omitted altogether by passing a NULL pointer and deleting the references to the parameter in ThreadFunc.

It is risky to pass the address of a local variable if the creating thread exits before the new thread, because the pointer becomes invalid. Instead, either pass a pointer to dynamically allocated memory or make the creating thread wait for the new thread to terminate. Data can also be passed from the creating thread to the new thread using global variables. With global variables, it is usually necessary to synchronize access by multiple threads. For more information about synchronization, see Synchronizing Execution of Multiple Threads.

In processes where a thread might create multiple threads to execute the same code, it is inconvenient to use global variables. For example, a process that enables the user to open several files at the same time can create a new thread for each file, with each of the threads executing the same thread function. The creating thread can pass the unique information (such as the file name) required by each instance of the thread function as an argument. You cannot use a single global variable for this purpose, but you could use a dynamically allocated string buffer.

The creating thread can use the arguments to CreateThread to specify the following:

  • The security attributes for the handle to the new thread. These security attributes include an inheritance flag that determines whether the handle can be inherited by child processes. The security attributes also include a security descriptor, which the system uses to perform access checks on all subsequent uses of the thread's handle before access is granted.
  • The initial stack size of the new thread. The thread's stack is allocated automatically in the memory space of the process; the system increases the stack as needed and frees it when the thread terminates.
  • A creation flag that enables you to create the thread in a suspended state. When suspended, the thread does not run until the ResumeThread function is called.

You can also create a thread by calling the CreateRemoteThread function. This function is used by debugger processes to create a thread that runs in the address space of the process being debugged.


Thread Stack Size

Each new thread receives its own stack space, consisting of both committed and reserved memory. The system will commit one page blocks from the reserved stack memory as needed, until the stack cannot grow any farther.

The default size for committed and reserved memory is specified in the executable file header. To specify a different default stack size, use the STACKSIZE statement in the module definition (.DEF) file. Your linker may also support a command-line option for setting the stack size. For more information, see the documentation included with your linker.

To increase the amount of stack space which is to be initially committed for a thread, specify the value in the dwStackSize parameter of the CreateThread function. This value is rounded to the nearest page and used to set the initial size of the committed memory. The call to CreateThread will fail if there is not enough memory to commit the number of bytes you request. If dwStackSize is smaller than the default reserve size, the new thread uses the default reserve size. If dwStackSize is larger than the default reserve size, the reserve size is rounded up to the nearest multiple of 1 MB.

The stack is freed when the thread terminates.


Thread Handles and Identifiers

When a new thread is created by the CreateThread or CreateRemoteThread function, a handle to the thread is returned. By default, this handle has full access rights, and — subject to security access checking — can be used in any of the functions that accept a thread handle. This handle can be inherited by child processes, depending on the inheritance flag specified when it is created. The handle can be duplicated by DuplicateHandle, which enables you to create a thread handle with a subset of the access rights. The handle is valid until closed, even after the thread it represents has been terminated.

The CreateThread and CreateRemoteThread functions also return an identifier that uniquely identifies the thread throughout the system. A thread can use the GetCurrentThreadId function to get its own thread identifier. The identifiers are valid from the time the thread is created until the thread has been terminated.

Windows 2000 and later: If you have a thread identifier, you can get the thread handle by calling the OpenThread function. OpenThread enables you to specify the handle's access rights and whether it can be inherited.

Windows NT 4.0 and earlier, Windows 95/98/Me: The Win32 API does not provide a way to get the thread handle from the thread identifier. If the handles were made available this way, the owning process could fail because another process unexpectedly performed an operation on one of its threads, such as suspending it, resuming it, adjusting its priority, or terminating it. Instead, you must request the handle from the thread creator or the thread itself.

A thread can use the GetCurrentThread function to retrieve a pseudo handle to its own thread object. This pseudo handle is valid only for the calling process; it cannot be inherited or duplicated for use by other processes. To get the real handle to the thread, given a pseudo handle, use the DuplicateHandle function.


Suspending Thread Execution

A thread can suspend and resume the execution of another thread using the SuspendThread and ResumeThread functions. While a thread is suspended, it is not scheduled for time on the processor.

The SuspendThread function is not particularly useful for synchronization because it does not control the point in the code at which the thread's execution is suspended. However, you might want to suspend a thread in a situation where you are waiting for user input that could cancel the work the thread is performing. If the user input cancels the work, have the thread exit; otherwise, call ResumeThread.

If a thread is created in a suspended state (with the CREATE_SUSPENDED flag), it does not begin to execute until another thread calls ResumeThread with a handle to the suspended thread. This can be useful for initializing the thread's state before it begins to execute. Suspending a thread at creation can be useful for one-time synchronization, because this ensures that the suspended thread will execute the starting point of its code when you call ResumeThread.

A thread can temporarily yield its execution for a specified interval by calling the Sleep or SleepEx functions This is useful particularly in cases where the thread responds to user interaction, because it can delay execution long enough to allow users to observe the results of their actions. During the sleep interval, the thread is not scheduled for time on the processor.

The SwitchToThread function is similar to Sleep and SleepEx, except that you cannot specify the interval. SwitchToThread allows the thread to give up its time slice.


Synchronizing Execution of Multiple Threads

To avoid race conditions and deadlocks, it is necessary to synchronize access by multiple threads to shared resources. Synchronization is also necessary to ensure that interdependent code is executed in the proper sequence.

The Win32 API provides a number of objects whose handles can be used to synchronize multiple threads. These objects include:

  • Console input buffers
  • Events
  • Mutexes
  • Processes
  • Semaphores
  • Threads
  • Timers

The state of each of these objects is either signaled or not signaled. When you specify a handle to any of these objects in a call to one of the wait functions, the execution of the calling thread is blocked until the state of the specified object becomes signaled.

Some of these objects are useful in blocking a thread until some event occurs. For example, a console input buffer handle is signaled when there is unread input, such as a keystroke or mouse button click. Process and thread handles are signaled when the process or thread terminates. This allows a process, for example, to create a child process and then block its own execution until the new process has terminated.

Other objects are useful in protecting shared resources from simultaneous access. For example, multiple threads can each have a handle to a mutex object. Before accessing a shared resource, the threads must call one of the wait functions to wait for the state of the mutex to be signaled. When the mutex becomes signaled, only one waiting thread is released to access the resource. The state of the mutex is immediately reset to not signaled so any other waiting threads remain blocked. When the thread is finished with the resource, it must set the state of the mutex to signaled to allow other threads to access the resource.

For the threads of a single process, critical-section objects provide a more efficient means of synchronization than mutexes. A critical section is used like a mutex to enable one thread at a time to use the protected resource. A thread can use the EnterCriticalSection function to request ownership of a critical section. If it is already owned by another thread, the requesting thread is blocked. A thread can use the TryEnterCriticalSection function to request ownership of a critical section, without blocking upon failure to obtain the critical section. After it receives ownership, the thread is free to use the protected resource. The execution of the other threads of the process is not affected unless they attempt to enter the same critical section.

The WaitForInputIdle function makes a thread wait until a specified process is initialized and waiting for user input with no input pending. Calling WaitForInputIdle can be useful for synchronizing parent and child processes, because CreateProcess returns without waiting for the child process to complete its initialization.

For more information, see Synchronization.


Multiple Threads and GDI Objects

To enhance performance, access to graphics device interface (GDI) objects (such as palettes, device contexts, regions, and the like) is not serialized. This creates a potential danger for processes that have multiple threads sharing these objects. For example, if one thread deletes a GDI object while another thread is using it, the results are unpredictable. This danger can be avoided simply by not sharing GDI objects. If sharing is unavoidable (or desirable), the application must provide its own mechanisms for synchronizing access. For more information about synchronizing access, see Synchronizing Execution of Multiple Threads.


Thread Local Storage

All threads of a process share the virtual address space and the global variables of that process. The local variables of a thread function are local to each thread that runs the function. However, the static or global variables used by that function have the same value for all threads. With thread local storage (TLS), you can create a unique copy of a variable for each thread. Using TLS, one thread allocates an index that can be used by any thread of the process to retrieve its unique copy.

Use the following steps to implement TLS:

  1. Use the TlsAlloc function during process or dynamic-link library (DLL) initialization to allocate a TLS index.
  2. For each thread that needs to use the TLS index, allocate dynamic storage, then use the TlsSetValue function to associate the index with a pointer to the dynamic storage.
  3. When you need a thread to access its storage, specify the TLS index in a call to the TlsGetValue function to retrieve the pointer.
  4. When each thread no longer needs the dynamic storage that it has associated with a TLS index, it must free the index. When all threads have finished using a TLS index, use the TlsFree function to free the index.

The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. This minimum is guaranteed to be at least 64 for all systems.

Windows 2000 and later: There is a limit of 1088 TLS indexes per process.
Windows NT 4.0 and earlier: There is a limit of 64 TLS indexes per process.

It is ideal to use TLS in a DLL. Perform the initial TLS operations in the DllMain function in the context of the process or thread attaching to the DLL. When a new process attaches to the DLL, call TlsAlloc in the entry-point function to allocate a TLS index for that process. Then store the TLS index in a global variable that is private to each attached process. When a new thread attaches to the DLL, allocate dynamic memory for that thread in the entry-point function, and use TlsSetValue with the TLS index from TlsAlloc to save private data to the index. Then you can use the TLS index in a call to TlsGetValue to access the private data for the calling thread from within any function in the DLL. When a process detaches from the DLL, call TlsFree.

For an example illustrating the use of thread local storage, see Using Thread Local Storage.


Creating Windows in Threads

Any thread can create a window. The thread that creates the window owns the window and its associated message queue. Therefore, the thread must provide a message loop to process the messages in its message queue. In addition, you must use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx in that thread, rather than the other wait functions, so that it can process messages. Otherwise, the system can become deadlocked when the thread is sent a message while it is waiting.

The AttachThreadInput function can be used 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 function 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.


Terminating a Thread

A thread executes until one of the following events occurs:

  • The thread calls the ExitThread function.
  • Any thread of the process calls the ExitProcess function.
  • The thread function returns.
  • Any thread calls the TerminateThread function with a handle to the thread.
  • Any thread calls the TerminateProcess function with a handle to the process.

The GetExitCodeThread function returns the termination status of a thread. While a thread is executing, its termination status is STILL_ACTIVE. When a thread terminates, its termination status changes from STILL_ACTIVE to the exit code of the thread. The exit code is either the value specified in the call to ExitThread, ExitProcess, TerminateThread, or TerminateProcess, or the value returned by the thread function.

When a thread terminates, the state of the thread object changes to signaled, releasing any other threads that had been waiting for the thread to terminate. For more about synchronization, see Synchronizing Execution of Multiple Threads.

If a thread is terminated by ExitThread, the system calls the entry-point function of each attached DLL with a value indicating that the thread is detaching from the DLL (unless you call the DisableThreadLibraryCalls function). If a thread is terminated by ExitProcess, the DLL entry-point functions are invoked once, to indicate that the process is detaching. DLLs are not notified when a thread is terminated by TerminateThread or TerminateProcess. For more information about DLLs, see Dynamic-Link Libraries.

Warning The TerminateThread and TerminateProcess functions should be used only in extreme circumstances, since they do not allow threads to clean up, do not notify attached DLLs, and do not free the initial stack. The following steps provide a better solution:

  • Create an event object using the CreateEvent function.
  • Create the threads.
  • Each thread monitors the event state by calling the WaitForSingleObject function. Use a wait time-out interval of zero.
  • Each thread terminates its own execution when the event is set to the signaled state (WaitForSingleObject returns WAIT_OBJECT_0).


Thread Times

The GetThreadTimes function obtains timing information for a thread. It returns the thread creation time, how much time the thread has been executing in kernel mode, and how much time the thread has been executing in user mode. These times do not include time spent executing system threads or waiting in a suspended or blocked state. If the thread has exited, GetThreadTimes returns the thread exit time.


Thread Security and Access Rights

Windows NT/Windows 2000 security enables you to control access to thread objects. For more information about security, see Access-Control Model.

You can specify a security descriptor for a thread when you call the CreateProcess, CreateProcessAsUser, CreateProcessWithLogonW, CreateThread, or CreateRemoteThread function. To retrieve a thread's security descriptor, call the GetSecurityInfo function. To change a thread's security descriptor, call the SetSecurityInfo function.

The handle returned by the CreateThread function has THREAD_ALL_ACCESS access to the thread object. When you call the GetCurrentThread function, the system returns a pseudohandle with the maximum access that the thread's security descriptor allows the caller.

The valid access rights for thread objects include the DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, and WRITE_OWNER standard access rights, in addition to the following thread-specific access rights.

Value | Meaning
SYNCHRONIZE | A standard right required to wait for the thread to exit.
THREAD_ALL_ACCESS | Specifies all possible access rights for a thread object.
THREAD_DIRECT_IMPERSONATION | Required for a server thread that impersonates a client.
THREAD_GET_CONTEXT | Required to read the context of a thread using GetThreadContext.
THREAD_IMPERSONATE | Required to use a thread's security information directly without calling it by using a communication mechanism that provides impersonation services.
THREAD_QUERY_INFORMATION | Required to read certain information from the thread object.
THREAD_SET_CONTEXT | Required to write the context of a thread.
THREAD_SET_INFORMATION | Required to set certain information in the thread object.
THREAD_SET_THREAD_TOKEN | Required to set the impersonation token for a thread.
THREAD_SUSPEND_RESUME | Required to suspend or resume a thread.
THREAD_TERMINATE | Required to terminate a thread.

You can request the ACCESS_SYSTEM_SECURITY access right to a thread object if you want to read or write the object's SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.


Child Processes

A child process is a process that is created by another process, called the parent process.

This section discusses the following topics:

  • Creating Processes
  • Setting Window Properties Using STARTUPINFO
  • Process Handles and Identifiers
  • Obtaining Additional Process Information
  • Inheritance
  • Environment Variables
  • Terminating a Process
  • Process Times
  • Process Security and Access Rights


Creating Processes

The CreateProcess function creates a new process, which runs independently of the creating process. However, for simplicity, the relationship is referred to as a parent-child relationship.

The following code fragment demonstrates how to create a process.

void main( VOID )
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );

    // Start the child process.
    if( !CreateProcess( NULL, // No module name (use command line).
        "MyChildProcess", // Command line.
        NULL,             // Process handle not inheritable.
        NULL,             // Thread handle not inheritable.
        FALSE,            // Set handle inheritance to FALSE.
        0,                // No creation flags.
        NULL,             // Use parent's environment block.
        NULL,             // Use parent's starting directory.
        &si,              // Pointer to STARTUPINFO structure.
        &pi )             // Pointer to PROCESS_INFORMATION structure.
    )
    {
        ErrorExit( "CreateProcess failed." );
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles.
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
}

If CreateProcess succeeds, it returns a PROCESS_INFORMATION structure containing handles and identifiers for the new process and its primary thread. The thread and process handles are created with full access rights, although access can be restricted if you specify security descriptors. When you no longer need these handles, close them by using the CloseHandle function.

You can also create a process using the CreateProcessAsUser function. This function allows you to specify the security context of the user account in which the process will execute.


Setting Window Properties Using STARTUPINFO

A parent process can specify properties associated with the main window of its child process. The CreateProcess function takes a pointer to a STARTUPINFO structure as one of its parameters. Use the members of this structure to specify characteristics of the child process's main window. The dwFlags member contains a bit field that determines which other members of the structure are used. This allows you to specify values for any subset of the window properties. The system uses default values for the properties you do not specify. The dwFlags member can also force a feedback cursor to be displayed during the initialization of the new process.

For GUI processes, the STARTUPINFO structure specifies the default values to be used the first time the new process calls the CreateWindow and ShowWindow functions to create and display an overlapped window. The following default values can be specified:

  • The width and height, in pixels, of the window created by CreateWindow.
  • The location, in screen coordinates of the window created by CreateWindow.
  • The nCmdShow parameter of ShowWindow.

For console processes, use the STARTUPINFO structure to specify window properties only when creating a new console (either using CreateProcess with CREATE_NEW_CONSOLE or with the AllocConsole function). The STARTUPINFO structure can be used to specify the following console window properties:

  • The size of the new console window, in character cells.
  • The location of the new console window, in screen coordinates.
  • The size, in character cells, of the new console's screen buffer.
  • The text and background color attributes of the new console's screen buffer.
  • The title of the new console's window.


Process Handles and Identifiers

When a new process is created by the CreateProcess function, handles of the new process and its primary thread are returned. These handles are created with full access rights, and — subject to security access checking — can be used in any of the functions that accept thread or process handles. These handles can be inherited by child processes, depending on the inheritance flag specified when they are created. The handles are valid until closed, even after the process or thread they represent has been terminated.

The CreateProcess function also returns an identifier that uniquely identifies the process throughout the system. A process can use the GetCurrentProcessId function to get its own process identifier. The identifier is valid from the time the process is created until the process has been terminated.

If you have a process identifier, you can get the process handle by calling the OpenProcess function. OpenProcess enables you to specify the handle's access rights and whether it can be inherited.

A process can use the GetCurrentProcess function to retrieve a pseudo handle to its own process object. This pseudo handle is valid only for the calling process; it cannot be inherited or duplicated for use by other processes. To get the real handle to the process, call the DuplicateHandle function.


Obtaining Additional Process Information

The Win32 API provides functions for obtaining information about processes. Some of these functions can be used only for the calling process, because they do not take a process handle as a parameter. You can use functions that take a process handle to obtain information about other processes.

  • To obtain the command-line string for the current process, use the GetCommandLine function.
  • To parse a Unicode command-line string obtained from the Unicode version of GetCommandLine, use the CommandLineToArgvW function.
  • To retrieve the STARTUPINFO structure specified when the current process was created, use the GetStartupInfo function.
  • To obtain the version information from the executable header, use the GetProcessVersion function.
  • To obtain the full path and file name for the executable file containing the process code, use the GetModuleFileName function.
  • To obtain the count of handles to graphical user interface (GUI) objects in use, use the GetGuiResources function.
  • To determine whether a process is being debugged, use the IsDebuggerPresent function.
  • To retrieve accounting information for all I/O operations performed by the process, use the GetProcessIoCounters function.


Inheritance

A child process can inherit several properties and resources from its parent process. You can also prevent a child process from inheriting properties from its parent process. The following can be inherited:

  • Open handles returned by the CreateFile function. This includes handles to files, console input buffers, console screen buffers, named pipes, serial communication devices, and mailslots.
  • Open handles to process, thread, mutex, event, semaphore, named-pipe, anonymous-pipe, and file-mapping objects.
  • Environment variables.
  • The current directory.
  • The console, unless the process is detached or a new console is created. A child console process also inherits the parent's standard handles, as well as access to the input buffer and the active screen buffer.

The child process does not inherit the following:

  • Priority class.
  • Handles returned by LocalAlloc, GlobalAlloc, HeapCreate, and HeapAlloc.
  • Pseudo handles, as in the handles returned by the GetCurrentProcess or GetCurrentThread function. These handles are valid only for the calling process.
  • DLL module handles returned by the LoadLibrary function.
  • GDI or USER handles, such as HBITMAP or HMENU.

Inheriting Handles

To cause a handle to be inherited, you must do two things:

  • Specify that the handle is to be inherited when you create, open, or duplicate the handle.
  • Specify that inheritable handles are to be inherited when you call the CreateProcess function.

This allows a child process to inherit some of its parent's handles, but not inherit others. For example, creation functions such as CreateProcess and CreateFile take a security attributes argument that determines whether the handle can be inherited. Open functions such as OpenMutex and OpenEvent take a handle inheritance flag that determines whether the handle can be inherited. The DuplicateHandle function takes a handle inheritance flag that determines whether the handle can be inherited.

When a child process is created, the fInheritHandles parameter of CreateProcess determines whether the inheritable handles of the parent process are inherited by the child process. An inherited handle refers to the same object in the child process as it does in the parent process. It also has the same value and access privileges. Therefore, when one process changes the state of the object, the change affects both processes. To use a handle, the child process must retrieve the handle value and "know" the object to which it refers. Usually, the parent process communicates this information to the child process through its command line, environment block, or some form of interprocess communication.

The DuplicateHandle function is useful if a process has an inheritable open handle that you do not want to be inherited by the child process. In this case, use DuplicateHandle to open a duplicate of the handle that cannot be inherited, then use the CloseHandle function to close the inheritable handle. You can also use the DuplicateHandle function to open an inheritable duplicate of a handle that cannot be inherited.

Inheriting Environment Variables

A child process inherits the environment variables of its parent process by default. However, CreateProcess enables the parent process to specify a different block of environment variables. For more information, see Environment Variables.

Inheriting the Current Directory

The GetCurrentDirectory function retrieves the current directory of the calling process. A child process inherits the current directory of its parent process by default. However, CreateProcess enables the parent process to specify a different current directory for the child process. To change the current directory of the calling process, use the SetCurrentDirectory function.


Environment Variables

Every process has an environment block that contains a set of environment variables and their values. The command processor provides the set command to display its environment block or to create new environment variables. Programs started by the command processor inherit the command processor's environment variables.

By default, a child process inherits the environment variables of its parent process. However, you can specify a different environment for the child process by creating a new environment block and passing a pointer to it as a parameter to the CreateProcess function.

The GetEnvironmentStrings function returns a pointer to the environment block of the calling process. This should be treated as a read-only block; do not modify it directly. Instead, use the SetEnvironmentVariable function to change an environment variable. When you are finished with the environment block obtained from GetEnvironmentStrings, call the FreeEnvironmentStrings function to free the block.

The GetEnvironmentVariable function determines whether a specified variable is defined in the environment of the calling process, and, if so, what its value is.

For more information, see the examples in Changing Environment Variables.


Terminating a Process

A process executes until one of the following events occurs:

  • Any thread of the process calls the ExitProcess function. This terminates all threads of the process.
  • The primary thread of the process returns. The primary thread can avoid terminating other threads by explicitly calling ExitThread before it returns. One of the remaining threads can still call ExitProcess to ensure that all threads are terminated.
  • The last thread of the process terminates.
  • Any thread calls the TerminateProcess function with a handle to the process. This terminates all threads of the process, without allowing them to clean up or save data.
  • For console processes, the default handler function calls ExitProcess when the console receives a CTRL+C or CTRL+BREAK signal. All console processes attached to the console receive these signals. Detached processes and GUI processes are not affected by CTRL+C or CTRL+BREAK signals. For more information, see SetConsoleCtrlHandler.
  • The user shuts down the system or logs off. Use the SetProcessShutdownParameters function to specify shutdown parameters, such as when a process should terminate relative to the other processes in the system. The GetProcessShutdownParameters function retrieves the current shutdown priority of the process and other shutdown flags.

When a process is terminated, all threads of the process are terminated immediately with no chance to run additional code. This means that the process does not execute code in termination handler blocks. For more information, see Structured Exception Handling.

The GetExitCodeProcess function returns the termination status of a process. While a process is executing, its termination status is STILL_ACTIVE. When a process terminates, its termination status changes from STILL_ACTIVE to the exit code of the process. The exit code is either the value specified in the call to ExitProcess or TerminateProcess, or the value returned by the main or WinMain function of the process. If a process is terminated due to a fatal exception, the exit code is the value of the exception that caused the termination. In addition, this value is used as the exit code for all the threads that were executing when the exception occurred.

When a process terminates, the state of the process object becomes signaled, releasing any threads that had been waiting for the process to terminate. For more about synchronization, see Synchronizing Execution of Multiple Threads.

Open handles to files or other resources are closed automatically when a process terminates. However, the objects themselves exist until all open handles to them are closed. This means that an object remains valid after a process closes, if another process has a handle to it.

If a process is terminated by ExitProcess, the system calls the entry-point function of each attached DLL with a value indicating that the process is detaching from the DLL. DLLs are not notified when a process is terminated by TerminateProcess. For more information about DLLs, see Dynamic-Link Libraries.

Warning The TerminateProcess function should be used only in extreme circumstances, since it does not allow threads to clean up or save data and does not notify attached DLLs. If you need to have one process terminate another process, the following steps provide a better solution:

  • Have both processes call the RegisterWindowMessage function to create a private message.
  • One process can terminate the other process by broadcasting the private message using the BroadcastSystemMessage function as follows:
    BroadcastSystemMessage(
    BSF_IGNORECURRENTTASK, // do not send message to this process
    BSM_APPLICATIONS,      // broadcast only to applications
    private message,       // message registered in previous step
    wParam,                // message-specific value
    lParam );              // message-specific value
  • The process receiving the private message calls ExitProcess to terminate its execution.

Note When the system is terminating a process, it does not terminate any child processes that the process has created.


Process Times

The GetProcessTimes function obtains timing information for a process. It returns the process creation time, how much time the process has been executing in kernel mode, and how much time the process has been executing in user mode. These times do not include time spent executing system threads or waiting in a suspended or blocked state. If the process has exited, GetProcessTimes returns the process exit time.


Process Security and Access Rights

Windows NT/Windows 2000 security enables you to control access to process objects. For more information about security, see Access-Control Model.

You can specify a security descriptor for a process when you call the CreateProcess, CreateProcessAsUser, or CreateProcessWithLogonW function. To retrieve a process's security descriptor, call the GetSecurityInfo function. To change a process's security descriptor, call the SetSecurityInfo function.

The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object. When you call the OpenProcess function, the system checks the requested access rights against the DACL in the process's security descriptor. When you call the GetCurrentProcess function, Windows NT returns a pseudohandle with the maximum access that the DACL allows to the caller.

The valid access rights for process objects include the DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, and WRITE_OWNER standard access rights, in addition to the following process-specific access rights.

Value | Meaning
PROCESS_ALL_ACCESS | Specifies all possible access rights for a process object.
PROCESS_CREATE_PROCESS | Required to create a process.
PROCESS_CREATE_THREAD | Required to create a thread.
PROCESS_DUP_HANDLE | Required to duplicate a handle.
PROCESS_QUERY_INFORMATION | Required to retrieve certain information about a process, such as its priority class.
PROCESS_SET_QUOTA | Required to set memory limits.
PROCESS_SET_INFORMATION | Required to set certain information about a process, such as its priority class.
PROCESS_TERMINATE | Required to terminate a process.
PROCESS_VM_OPERATION | Required to perform an operation on the address space of a process.
PROCESS_VM_READ | Required to read memory in a process.
PROCESS_VM_WRITE | Required to write to memory in a process.
SYNCHRONIZE | A standard right required to wait for the process to terminate.

You can request the ACCESS_SYSTEM_SECURITY access right to a process object if you want to read or write the object's SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.


Process Working Set

The working set of a program is a collection of those pages in its virtual address space that have been recently referenced. It includes both shared and private data. The shared data includes pages that contain all instructions your application executes, including those in your DLLs and the system DLLs. As the working set size increases, memory demand increases.

A process has an associated minimum working set size and maximum working set size. Each time you call CreateProcess, it reserves the minimum working set size for the process. The virtual memory manager attempts to keep enough memory for the minimum working set resident when the process is active, but keeps no more than the maximum size.

To get the requested minimum and maximum sizes of the working set for your application, call the GetProcessWorkingSetSize function.

The system sets the default working set sizes. You can also modify the working set sizes using the SetProcessWorkingSetSize function. Setting these values is not a guarantee that the memory will be reserved or resident. Be careful about requesting too large a minimum or maximum working set size, because doing so can degrade system performance.


Thread Pooling

There are many applications that create threads that spend a great deal of time in the sleeping state waiting for an event to occur. Other threads may enter a sleeping state only to be awakened periodically to poll for a change or update status information. Thread pooling enables you to use threads more efficiently by providing your application with a pool of worker threads that are managed by the system. At least one thread monitors the status of all wait operations queued to the thread pool. When a wait operation has completed, a worker thread from the thread pool executes the corresponding callback function.

You can also queue work items that are not related to a wait operation to the thread pool. To request that a work item be handled by a thread in the thread pool, call the QueueUserWorkItem function. This function takes a parameter to the function that will be called by the thread selected from the thread pool. There is no way to cancel a work item after it has been queued.

Timer-queue timers and registered wait operations also use the thread pool. Their callback functions are queued to the thread pool. You can also use the BindIoCompletionCallback function to post asynchronous I/O operations. On completion of the I/O , the callback is executed by a thread pool thread.

The thread pool is created the first time you call QueueUserWorkItem or BindIoCompletionCallback, or when a timer-queue timer or registered wait operation queues a callback function. The number of threads that can be created in the thread pool is limited only by available memory. Each thread uses the default stack size and runs at the default priority.

There are two types of worker threads in the thread pool: I/O and non-I/O. An I/O worker thread is a thread that waits in an alertable wait state. Work items are queued to I/O worker threads as asynchronous procedure calls (APC). You should queue a work item to an I/O worker thread if it should be executed in a thread that waits in an alertable state.

A non-I/O worker thread waits on I/O completion ports. Using non-I/O worker threads is more efficient than using I/O worker threads. Therefore, you should use non-I/O worker threads whenever possible. Both I/O and non-I/O worker threads do not exit if there are pending asynchronous I/O requests. Both types of threads can be used by work items that initiate asynchronous I/O completion requests. However, avoid posting asynchronous I/O completion requests in non-I/O worker threads if they could take a long time to complete.

To use thread pooling, the work items and all the functions they call must be thread-pool safe. A safe function does not assume that thread executing it is a dedicated or persistent thread. In general, you should avoid thread local storage and queueing asynchronous calls that require a persistent thread, such as the RegNotifyChangeKeyValue function. However, such functions can be queued to a persistent worker thread using QueueUserWorkItem with the WT_EXECUTEINPERSISTENTTHREAD option.

Note that thread pooling is not compatible with the single-threaded apartment (STA) model.


Job Objects

A job object allows groups of processes to be managed as a unit. Job objects are namable, securable, sharable objects that control attributes of the processes associated with them. Operations performed on the job object affect all processes associated with the job object.

To create a job object, use the CreateJobObject function. When the job is created, there are no associated processes. To associate a process with a job, use the AssignProcessToJobObject function. After you associate a process with a job, the association cannot be broken. By default, processes created by a process associated with a job (child processes) are associated with the job. If the job has the extended limit JOB_OBJECT_LIMIT_BREAKAWAY_OK and the process was created with the CREATE_BREAKAWAY_FROM_JOB flag, its child processess are not associated with the job. If the job has the extended limit JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK, no child processes are associated with the job.

To determine if a process is running in a job, use the IsProcessInJob function.

A job can enforce limits on each associated process, such as the working set size, process priority, end-of-job time limit, and so on. To set limits for a job object, use the SetInformationJobObject function. If a process associated with a job attempts to increase its working set size or process priority, the function calls are silently ignored.

The job object also records basic accounting information for all its associated processes, including those that have terminated. To retrieve this accounting information, use the QueryInformationJobObject function.

To terminate all processes currently associated with a job object, use the TerminateJobObject function.

To close a job object handle, use the CloseHandle function. The job object is destroyed when its last handle has been closed. If there are running processes still associated with the job when it is destroyed, they will continue to run even after the job is destroyed.

If a tool is to manage a process tree that uses job objects, both the tool and the members of the process tree must cooperate. Use one of the following options:

  1. The tool could use the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK limit. If the tool uses this limit, it cannot monitor an entire process tree. The tool can monitor only the processes it adds to the job. If these processes create child processes, they are not associated with the job. In this option, child processes can be associated with other job objects.
  2. The tool could use the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit. If the tool uses this limit, it can monitor the entire process tree, except for those processes that any member of the tree explicitly breaks away from the tree. A member of the tree can create a child process in a new job object by calling the CreateProcess function with the CREATE_BREAKAWAY_FROM_JOB flag, then calling the AssignProcessToJobObject function. Otherwise, the member must handle cases in which AssignProcessToJobObject fails.

    The CREATE_BREAKAWAY_FROM_JOB flag has no effect if the tree is not being monitored by the tool. Therefore, this is the preferred option, but it requires advance knowledge of the processes being monitored.

  3. The tool could prevent breakaways of any kind. In this option, the tool can monitor the entire process tree. However, if a process associated with the job tries to call AssignProcessToJobObject, the call will fail. If the process was not designed to be associated with a job, this failure may be unexpected.


Job Object Security and Access Rights

Windows NT/Windows 2000 security enables you to control access to job objects. For more information about security, see Access-Control Model.

You can specify a security descriptor for a job object when you call the CreateJobObject function. To get or set the security descriptor for a job object, call the GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, or SetSecurityInfo function.

The handle returned by CreateJobObject has JOB_OBJECT_ALL_ACCESS access to the job object. When you call the OpenJobObject function, the system checks the requested access rights against the object's security descriptor.

The valid access rights for job objects include the DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, and WRITE_OWNER standard access rights, in addition to the following job-specific access rights.

Value | Meaning
JOB_OBJECT_ASSIGN_PROCESS | Required to call the AssignProcessToJobObject function to assign processes to the job object.
JOB_OBJECT_SET_ATTRIBUTES | Required to call the SetInformationJobObject function to set the attributes of the job object.
JOB_OBJECT_QUERY | Required to call the QueryInformationJobObject function to query job object attributes and accounting information.
JOB_OBJECT_TERMINATE | Required to call the TerminateJobObject function to terminate all processes in the job object.
JOB_OBJECT_SET_SECURITY_ATTRIBUTES | Required to call the SetInformationJobObject function with the JobObjectSecurityLimitInformation information class to set security limitations on the processes associated with the job object.
JOB_OBJECT_ALL_ACCESS | Combines all valid job object access rights.

You can request the ACCESS_SYSTEM_SECURITY access right to a job object if you want to read or write the object's SACL. For more information, see Access-Control Lists (ACLs) and SACL Access Right.


Fibers

A fiber is a unit of execution that must be manually scheduled by the application. Fibers run in the context of the threads that schedule them. Each thread can schedule multiple fibers. In general, fibers do not provide advantages over a well-designed multithreaded application. However, using fibers can make it easier to port applications that were designed to schedule their own threads.

From a system standpoint, a fiber assumes the identity of the thread that created it. For example, if a fiber accesses thread local storage (TLS), it is accessing the thread local storage of the thread that created it. In addition, if a fiber calls the ExitThread function, the thread that created it exits. However, a fiber does not have all the same state information associated with it as that associated with a thread. The only state information maintained for a fiber is its stack, a subset of its registers, and the fiber data provided during fiber creation. The saved registers are the set of registers typically preserved across a function call.

Fibers are not preemptively scheduled. You schedule a fiber by switching to it from another fiber. The system still schedules threads to run. When a thread running fibers is preempted, its currently running fiber is preempted. The fiber runs when its thread runs.

Before scheduling the first fiber, call the ConvertThreadToFiber function to create an area in which to save fiber state information. The calling thread is now the currently executing fiber. The stored state information for this fiber includes the fiber data passed as an argument to ConvertThreadToFiber.

The CreateFiber function is used to create a new fiber from an existing fiber; the call requires the stack size, the starting address, and the fiber data. The starting address is typically a user-supplied function, called the fiber function, that takes one parameter (the fiber data) and does not return a value. If your fiber function returns, the thread running the fiber exits. To execute any fiber created with CreateFiber, call the SwitchToFiber function. You can call SwitchToFiber with the address of a fiber created by a different thread. To do this, you must have the address returned to the other thread when it called CreateFiber and you must use proper synchronization.

A fiber can retrieve the fiber data by calling the GetFiberData macro. A fiber can retrieve the fiber address at any time by calling the GetCurrentFiber macro.

To clean up the data associated with a fiber, call the DeleteFiber function. You must take care when calling DeleteFiber. If you call DeleteFiber for a fiber created by another thread, you can cause the other thread to terminate abnormally. If DeleteFiber is called from the currently running fiber, its thread calls ExitThread.


Using Processes and Threads

  • Creating a child process with redirected input and output
  • Changing environment variables
  • Using thread local storage


Creating a Child Process with Redirected Input and Output

The example in this topic demonstrates how to create a child process from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process's standard input and output handles.

The CreatePipe function uses the SECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the SetStdHandle function, which makes them the standard handles inherited by the child process. After the child process is created, SetStdHandle is used again to restore the original standard handles for the parent process.

The parent process uses the other ends of the pipes to write to the child process's input and read the child process's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle to create a duplicate of the application-defined hChildStdinWr global variable that cannot be inherited. It then uses CloseHandle to close the inheritable handle. For more information, see Pipes.

The following is the parent process.

#include <stdio.h>
#include <windows.h>

#define BUFSIZE 4096

HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
   hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
   hInputFile, hSaveStdin, hSaveStdout;

BOOL CreateChildProcess(VOID);
VOID WriteToPipe(VOID);
VOID ReadFromPipe(VOID);
VOID ErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);

DWORD main(int argc, char *argv[])
{
   SECURITY_ATTRIBUTES saAttr;
   BOOL fSuccess;

// Set the bInheritHandle flag so pipe handles are inherited.

   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
   saAttr.bInheritHandle = TRUE;
   saAttr.lpSecurityDescriptor = NULL;

   // The steps for redirecting child process's STDOUT:
   //     1. Save current STDOUT, to be restored later.
   //     2. Create anonymous pipe to be STDOUT for child process.
   //     3. Set STDOUT of the parent process to be write handle to
   //        the pipe, so it is inherited by the child process.
   //     4. Create a noninheritable duplicate of the read handle and
   //        close the inheritable read handle.

// Save the handle to the current STDOUT.

   hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Create a pipe for the child process's STDOUT.

   if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
      ErrorExit("Stdout pipe creation failed\n");

// Set a write handle to the pipe to be STDOUT.

   if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
      ErrorExit("Redirecting STDOUT failed");

// Create noninheritable read handle and close the inheritable read
// handle.

    fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
        GetCurrentProcess(), &hChildStdoutRdDup , 0,
        FALSE,
        DUPLICATE_SAME_ACCESS);
    if( !fSuccess )
        ErrorExit("DuplicateHandle failed");
    CloseHandle(hChildStdoutRd);

   // The steps for redirecting child process's STDIN:
   //     1.  Save current STDIN, to be restored later.
   //     2.  Create anonymous pipe to be STDIN for child process.
   //     3.  Set STDIN of the parent to be the read handle to the
   //         pipe, so it is inherited by the child process.
   //     4.  Create a noninheritable duplicate of the write handle,
   //         and close the inheritable write handle.

// Save the handle to the current STDIN.

   hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);

// Create a pipe for the child process's STDIN.

   if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
      ErrorExit("Stdin pipe creation failed\n");

// Set a read handle to the pipe to be STDIN.

   if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
      ErrorExit("Redirecting Stdin failed");

// Duplicate the write handle to the pipe so it is not inherited.

   fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
      GetCurrentProcess(), &hChildStdinWrDup, 0,
      FALSE,                  // not inherited
      DUPLICATE_SAME_ACCESS);
   if (! fSuccess)
      ErrorExit("DuplicateHandle failed");

   CloseHandle(hChildStdinWr);

// Now create the child process.

   if (! CreateChildProcess())
      ErrorExit("Create process failed");

// After process creation, restore the saved STDIN and STDOUT.

   if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
      ErrorExit("Re-redirecting Stdin failed\n");

   if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
      ErrorExit("Re-redirecting Stdout failed\n");

// Get a handle to the parent's input file.

   if (argc > 1)
      hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,
         OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
   else
      hInputFile = hSaveStdin;

   if (hInputFile == INVALID_HANDLE_VALUE)
      ErrorExit("no input file\n");

// Write to pipe that is the standard input for a child process.

   WriteToPipe();

// Read from pipe that is the standard output for child process.

   ReadFromPipe();

   return 0;
}

BOOL CreateChildProcess()
{
   PROCESS_INFORMATION piProcInfo;
   STARTUPINFO siStartInfo;

// Set up members of the PROCESS_INFORMATION structure.

   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

// Set up members of the STARTUPINFO structure.

   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   siStartInfo.cb = sizeof(STARTUPINFO);

// Create the child process.

   return CreateProcess(NULL,
      "child",       // command line
      NULL,          // process security attributes
      NULL,          // primary thread security attributes
      TRUE,          // handles are inherited
      0,             // creation flags
      NULL,          // use parent's environment
      NULL,          // use parent's current directory
      &siStartInfo,  // STARTUPINFO pointer
      &piProcInfo);  // receives PROCESS_INFORMATION
}

VOID WriteToPipe(VOID)
{
   DWORD dwRead, dwWritten;
   CHAR chBuf[BUFSIZE];

// Read from a file and write its contents to a pipe.

   for (;;)
   {
      if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||
         dwRead == 0) break;
      if (! WriteFile(hChildStdinWrDup, chBuf, dwRead,
         &dwWritten, NULL)) break;
   }

// Close the pipe handle so the child process stops reading.

   if (! CloseHandle(hChildStdinWrDup))
      ErrorExit("Close pipe failed\n");
}

VOID ReadFromPipe(VOID)
{
   DWORD dwRead, dwWritten;
   CHAR chBuf[BUFSIZE];
   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Close the write end of the pipe before reading from the
// read end of the pipe.

   if (!CloseHandle(hChildStdoutWr))
      ErrorExit("Closing handle failed");

// Read output from the child process, and write to parent's STDOUT.

   for (;;)
   {
      if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead,
         NULL) || dwRead == 0) break;
      if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))
         break;
   }
}

VOID ErrorExit (LPTSTR lpszMessage)
{
   fprintf(stderr, "%s\n", lpszMessage);
   ExitProcess(0);
}

// The code for the child process.

#include <windows.h>
#define BUFSIZE 4096

VOID main(VOID)
{
   CHAR chBuf[BUFSIZE];
   DWORD dwRead, dwWritten;
   HANDLE hStdin, hStdout;
   BOOL fSuccess;

   hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
   hStdin = GetStdHandle(STD_INPUT_HANDLE);
   if ((hStdout == INVALID_HANDLE_VALUE) ||
      (hStdin == INVALID_HANDLE_VALUE))
      ExitProcess(1);

   for (;;)
   {
   // Read from standard input.
      fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
      if (! fSuccess || dwRead == 0)
         break;

   // Write to standard output.
      fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
      if (! fSuccess)
         break;
   }
}


Changing Environment Variables

Each process has an environment block associated with it. The environment block consists of a null-terminated block of null-terminated strings (meaning there are two null bytes at the end of the block), where each string is in the form:

name=value

All strings in the environment block must be sorted alphabetically by name. The sort is case-insensitive, Unicode order, without regard to locale. Because the equal sign is a separator, it must not be used in the name of an environment variable.

By default, a child process inherits a copy of the environment block of the parent process. The following example demonstrates how to create a new environment block to pass to a child process.

LPTSTR lpszCurrentVariable;
BOOL fSuccess;

// Copy environment strings into an environment block.

lpszCurrentVariable = tchNewEnv;
if (lstrcpy(lpszCurrentVariable, "API=Win32") == NULL)
   ErrorExit("lstrcpy failed");

lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
if (lstrcpy(lpszCurrentVariable, "OperatingSystem=Windows") == NULL)
   ErrorExit("lstrcpy failed");

// Terminate the block with a NULL byte.

lpszCurrentVariable += lstrlen(lpszCurrentVariable) + 1;
*lpszCurrentVariable = '\0';

// Create the child process, specifying a new environment block.

fSuccess = CreateProcess(NULL, "childenv", NULL, NULL, TRUE, 0,
   (LPVOID) tchNewEnv,        // new environment block
   NULL, &siStartInfo, &piProcInfo);

if (! fSuccess)
    ErrorExit("CreateProcess failed");

If you want the child process to inherit most of the parent's environment with only a few changes, save the current values, make changes for the child process to inherit, create the child process, and then restore the saved values, as shown following.

LPTSTR lpszOldValue;
TCHAR tchBuf[BUFSIZE];
BOOL fSuccess;

// lpszOldValue gets current value of "varname", or NULL if "varname"
// environment variable does not exist. Set "varname" to new value,
// create child process, then use SetEnvironmentVariable to restore
// original value of "varname". If lpszOldValue is NULL, the "varname"
// variable will be deleted.

lpszOldValue = ((GetEnvironmentVariable("varname",
    tchBuf, BUFSIZE) > 0) ? tchBuf : NULL);

// Set a value for the child process to inherit.

if (! SetEnvironmentVariable("varname", "newvalue"))
   ErrorExit("SetEnvironmentVariable failed");

// Create a child process.

fSuccess = CreateProcess(NULL, "childenv", NULL, NULL, TRUE, 0,
   NULL,     // inherit parent's environment
   NULL, &siStartInfo, &piProcInfo);
if (! fSuccess)
   ErrorExit("CreateProcess failed");

// Restore the parent's environment.

if (! SetEnvironmentVariable("varname", lpszOldValue))
   ErrorExit("SetEnvironmentVariable failed");

The following example, taken from a console process, prints the contents of the process's environment block.

LPTSTR lpszVariable;
LPVOID lpvEnv;

// Get a pointer to the environment block.

lpvEnv = GetEnvironmentStrings();

// Variable strings are separated by NULL byte, and the block is
// terminated by a NULL byte.

for (lpszVariable = (LPTSTR) lpvEnv; *lpszVariable; lpszVariable++)
{
   while (*lpszVariable)
      putchar(*lpszVariable++);
   putchar('\n');
}


Using Thread Local Storage

Thread local storage (TLS) enables multiple threads of the same process to use an index allocated by the TlsAlloc function to store and retrieve a value that is local to the thread. In this example, an index is allocated when the process starts. When each thread starts, it allocates a block of dynamic memory and stores a pointer to this memory by using the TLS index. The TLS index is used by the locally defined CommonFunc function to access the data local to the calling thread. Before each thread terminates, it releases its dynamic memory.

#include <stdio.h>
#include <windows.h>

#define THREADCOUNT 4
DWORD dwTlsIndex;

VOID ErrorExit(LPTSTR);

VOID CommonFunc(VOID)
{
   LPVOID lpvData;

// Retrieve a data pointer for the current thread.

   lpvData = TlsGetValue(dwTlsIndex);
   if ((lpvData == 0) && (GetLastError() != 0))
      ErrorExit("TlsGetValue error");

// Use the data stored for the current thread.

   printf("common: thread %d: lpvData=%lx\n",
      GetCurrentThreadId(), lpvData);

   Sleep(5000);
}

DWORD WINAPI ThreadFunc(VOID)
{
   LPVOID lpvData;

// Initialize the TLS index for this thread.

   lpvData = (LPVOID) LocalAlloc(LPTR, 256);
   if (! TlsSetValue(dwTlsIndex, lpvData))
      ErrorExit("TlsSetValue error");

   printf("thread %d: lpvData=%lx\n", GetCurrentThreadId(), lpvData);

   CommonFunc();

// Release the dynamic memory before the thread returns.

   lpvData = TlsGetValue(dwTlsIndex);
   if (lpvData != 0)
      LocalFree((HLOCAL) lpvData);

   return 0;
}

DWORD main(VOID)
{
   DWORD IDThread;
   HANDLE hThread[THREADCOUNT];
   int i;

// Allocate a TLS index.

   if ((dwTlsIndex = TlsAlloc()) == -1)
      ErrorExit("TlsAlloc failed");

// Create multiple threads.

   for (i = 0; i < THREADCOUNT; i++)
   {
      hThread[i] = CreateThread(NULL, // no security attributes
         0,                           // use default stack size
         (LPTHREAD_START_ROUTINE) ThreadFunc, // thread function
         NULL,                    // no thread function argument
         0,                       // use default creation flags
         &IDThread);              // returns thread identifier

   // Check the return value for success.
      if (hThread[i] == NULL)
         ErrorExit("CreateThread error\n");
   }

   for (i = 0; i < THREADCOUNT; i++)
      WaitForSingleObject(hThread[i], INFINITE);

   return 0;
}

VOID ErrorExit (LPTSTR lpszMessage)
{
   fprintf(stderr, "%s\n", lpszMessage);
   ExitProcess(0);
}


Process and Thread Reference

The following elements are used with processes and threads.

  • Process and Thread Functions
  • Process and Thread Structures
  • Process and Thread Macros


Process and Thread Functions

The following functions are used with processes.

Function | Description
CommandLineToArgvW | Parses a Unicode command-line string.
CreateProcess | Creates a new process and its primary thread.
CreateProcessAsUser | Creates a new process and its primary thread. The new process runs in the security context of the specified user.
CreateProcessWithLogonW | Creates a new process and its primary thread. The new process then runs the specified executable file in the security context of the specified credentials (user, domain, and password).
ExitProcess | Ends a process and all its threads.
FreeEnvironmentStrings | Frees a block of environment strings.
GetCommandLine | Retrieves the command-line string for the current process.
GetCurrentProcess | Retrieves a pseudo handle for the current process.
GetCurrentProcessId | Retrieves the process identifier of the calling process.
GetEnvironmentStrings | Retrieves the environment block for the current process.
GetEnvironmentVariable | Retrieves the value of the specified variable from the environment block of the calling process.
GetExitCodeProcess | Retrieves the termination status of the specified process.
GetGuiResources | Retrieves the count of handles to graphical user interface (GUI) objects in use by the specified process.
GetPriorityClass | Retrieves the priority class for the specified process.
GetProcessAffinityMask | Retrieves a process affinity mask for the specified process and the system affinity mask for the system.
GetProcessIoCounters | Retrieves accounting information for all I/O operations performed by the specified process.
GetProcessPriorityBoost | Retrieves the priority boost control state of the specified process.
GetProcessShutdownParameters | Retrieves shutdown parameters for the currently calling process.
GetProcessTimes | Retrieves timing information about for the specified process.
GetProcessVersion | Retrieves the major and minor version numbers of the system on which the specified process expects to run.
GetProcessWorkingSetSize | Retrieves the minimum and maximum working set sizes of the specified process.
GetStartupInfo | Retrieves the contents of the STARTUPINFO structure that was specified when the calling process was created.
OpenProcess | Opens an existing process object.
SetEnvironmentVariable | Sets the value of an environment variable for the current process.
SetPriorityClass | Sets the priority class for the specified process.
SetProcessAffinityMask | Sets a processor affinity mask for the threads of a specified process.
SetProcessPriorityBoost | Disables the ability of the system to temporarily boost the priority of the threads of the specified process.
SetProcessShutdownParameters | Sets shutdown parameters for the currently calling process.
SetProcessWorkingSetSize | Sets the minimum and maximum working set sizes for the specified process.
TerminateProcess | Terminates the specified process and all of its threads.

The following functions are used with threads.

Function | Description
AttachThreadInput | Attaches the input processing mechanism of one thread to that of another thread.
CreateRemoteThread | Creates a thread that runs in the virtual address space of another process.
CreateThread | Creates a thread to execute within the virtual address space of the calling process.
ExitThread | Ends a thread.
GetCurrentThread | Retrieves a pseudo handle for the current thread.
GetCurrentThreadId | Retrieves the thread identifier of the calling thread.
GetExitCodeThread | Retrieves the termination status of the specified thread.
GetThreadPriority | Retrieves the priority value for the specified thread.
GetThreadPriorityBoost | Retrieves the priority boost control state of the specified thread.
GetThreadTimes | Retrieves timing information for the specified thread.
OpenThread | Opens an existing thread object.
ResumeThread | Decrements a thread's suspend count.
SetThreadAffinityMask | Sets a processor affinity mask for the specified thread.
SetThreadIdealProcessor | Specifies a preferred processor for a thread.
SetThreadPriority | Sets the priority value for the specified thread.
SetThreadPriorityBoost | Disables the ability of the system to temporarily boost the priority of a thread.
Sleep | Suspends the execution of the current thread for a specified interval.
SleepEx | Suspends the current thread until the specified condition is met.
SuspendThread | Suspends the specified thread.
SwitchToThread | Causes the calling thread to yield execution to another thread that is ready to run on the current processor.
TerminateThread | Terminates a thread.
ThreadProc | An application-defined function that serves as the starting address for a thread.
TlsAlloc | Allocates a thread local storage (TLS) index.
TlsFree | Releases a TLS index.
TlsGetValue | Retrieves the value in the calling thread's TLS slot for a specified TLS index.
TlsSetValue | Stores a value in the calling thread's TLS slot for a specified TLS index.
WaitForInputIdle | Waits until the specified process is waiting for user input with no input pending, or until the time-out interval has elapsed.

The following functions are used with job objects.

Function | Description
AssignProcessToJobObject | Associates a process with an existing job object.
CreateJobObject | Creates or opens a job object.
IsProcessInJob | Determines if the process is running in the specified job.
OpenJobObject | Opens an existing job object.
QueryInformationJobObject | Retrieves limit and job state information from the job object.
SetInformationJobObject | Set limits for a job object.
TerminateJobObject | Terminates all processes currently associated with the job.
UserHandleGrantAccess | Grants or denies access to a handle to a User object to a job that has a user-interface restriction.

The following functions are used in thread pooling.

Function | Description
BindIoCompletionCallback | Binds the specified file handle to the thread pool's I/O completion port.
QueueUserWorkItem | Queues a work item to a worker thread in the thread pool.

The following functions are used with fibers.

Function | Description
ConvertThreadToFiber | Converts the current thread into a fiber.
CreateFiber | Allocates a fiber object, assigns it a stack, and sets up execution to begin at the specified start address.
DeleteFiber | Deletes an existing fiber.
FiberProc | An application-defined function used with the CreateFiber function.
SwitchToFiber | Schedules a fiber.

Obsolete Functions

These functions are provided only for compatibility with 16-bit versions of Windows.

WinExec


AssignProcessToJobObject

The AssignProcessToJobObject function associates a process with an existing job object.

BOOL AssignProcessToJobObject(
  HANDLE hJob,     // handle to job
  HANDLE hProcess  // handle to process
);

Parameters

hJob
[in] Handle to the job object to which the process will be associated. The CreateJobObject or OpenJobObject function returns this handle. The handle must have the JOB_OBJECT_ASSIGN_PROCESS access right associated with it. For more information, see Job Object Security and Access Rights.
hProcess
[in] Handle to the process to associate with the job object. The process must not already be assigned to a job. The handle must have PROCESS_SET_QUOTA and PROCESS_TERMINATE access to the process. For more information, see Process Security and Access Rights.

Terminal Services: All processes within a job must run within the same session.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

After you associate a process with a job object using AssignProcessToJobObject, the process is subject to the limits set for the job. To set limits for a job, use the SetInformationJobObject function.

If the job has a user-mode time limit, and the time limit has been exhausted, AssignProcessToJobObject fails and the specified process is terminated. If the time limit would be exceeded by associating the process, AssignProcessToJobObject still succeeds. However, the time limit violation will be reported. If the job has an active process limit, and the limit would be exceeded by associating this process, AssignProcessToJobObject fails, and the specified process is terminated.

Memory operations performed by a process associated with a job that has a memory limit are subject to the memory limit. Memory operations performed by the process before it was associated with the job are not examined by AssignProcessToJobObject.

If the process is already running and the job has security limitations, AssignProcessToJobObject may fail. For example, if the primary token of the process contains the local administrators group, but the job object has the security limitation JOB_OBJECT_SECURITY_NO_ADMIN, the function fails. If the job has the security limitation JOB_OBJECT_SECURITY_ONLY_TOKEN, the process must be created suspended. To create a suspended process, call the CreateProcess function with the CREATE_SUSPENDED flag.

A process can be associated only with a single job. A process inherits limits from the job it is associated with and adds its accounting information to the job. If a process is associated with a job, all processes it creates are associated with that job by default. To create a process that is not part of the same job, call the CreateProcess function with the CREATE_BREAKAWAY_FROM_JOB flag.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, Processes and Threads Overview, CreateJobObject, CreateProcess, OpenJobObject, SetInformationJobObject


AttachThreadInput

The AttachThreadInput function attaches the input processing mechanism of one thread to that of another thread.

BOOL AttachThreadInput(
  DWORD idAttach,    // thread to attach
  DWORD idAttachTo,  // thread to attach to
  BOOL fAttach       // attach or detach
);

Parameters

idAttach
[in] Specifies the identifier of the thread to be attached to another thread. The thread to be attached cannot be a system thread.
idAttachTo
[in] Specifies the identifier of the thread to be attached to. This thread cannot be a system thread.

A thread cannot attach to itself. Therefore, idAttachTo cannot equal idAttach.

fAttach
[in] Specifies whether to attach or detach the threads. If this parameter is TRUE, the two threads are attached. If the parameter is FALSE, the threads are detached.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. There is no extended error information; do not call GetLastError.

Remarks

Windows created in different threads typically process input independently of each other. That is, they have their own input states (focus, active, capture windows, key state, queue status, and so on), and they are not synchronized with the input processing of other threads. By using the AttachThreadInput function, a thread can attach its input processing to another thread. This also allows threads to share their input states, so they can call the SetFocus function to set the keyboard focus to a window of a different thread. This also allows threads to get key-state information. These capabilities are not generally possible.

The AttachThreadInput function fails if either of the specified threads does not have a message queue. The system creates a thread's message queue when the thread makes its first call to one of the Win32 USER or GDI functions. The AttachThreadInput function also fails if a journal record hook is installed. Journal record hooks attach all input queues together.

Note that key state, which can be ascertained by calls to the GetKeyState or GetKeyboardState function, is reset after a call to AttachThreadInput.

Windows NT/2000 or later: You cannot attach a thread to a thread in another desktop.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetCurrentThreadId, GetKeyState, GetKeyboardState, GetWindowThreadProcessId, SetFocus


BindIoCompletionCallback

The BindIoCompletionCallback function binds the specified file handle to the thread pool's I/O completion port. On completion of the I/O request, a non-I/O worker thread will execute the callback function.

BOOL BindIoCompletionCallback(
  HANDLE FileHandle,                         // handle to file
  LPOVERLAPPED_COMPLETION_ROUTINE Function,  // callback
  ULONG Flags                                // reserved
);

Parameters

FileHandle
[in] Handle to a file opened for overlapped I/O completion. This handle is returned by the CreateFile function, with FILE_FLAG_OVERLAPPED flag.
Function
[in] Pointer to the callback function to be executed in a non-I/O worker thread when the I/O operation is complete. This callback function must not call the TerminateThread function.

For more information about the completion routine, see FileIOCompletionRoutine.

Flags
Reserved; must be zero.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Be sure that the thread that initiates the asynchronous I/O request does not terminate before the request is completed. Also, if a function in a DLL is queued to a worker thread, be sure that the function has completed execution before the DLL is unloaded.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, FileIOCompletionRoutine, Thread Pooling


CommandLineToArgvW

The CommandLineToArgvW function parses a Unicode command-line string. It returns a pointer to a set of Unicode argument strings and a count of arguments, similar to the standard C run-time argv and argc values. The function provides a way to obtain a Unicode set of argv and argc values from a Unicode command-line string.

LPWSTR * CommandLineToArgvW(
  LPCWSTR lpCmdLine,  // pointer to a command-line string
  int *pNumArgs       // receives the argument count
);

Parameters

lpCmdLine
[in] Pointer to a null-terminated Unicode command-line string. An application will usually directly pass on the value returned by a call to the GetCommandLineW function.

If this parameter is the empty string, "", the function returns the path to the current executable file.

pNumArgs
[out] Pointer to an integer variable that receives the count of arguments parsed.

Return Values

If the function succeeds, the return value is a non-NULL pointer to the constructed argument list, which is an array of Unicode strings.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

It is the caller's responsibility to free the memory used by the argument list when it is no longer needed. To free the memory, use a single call to the GlobalFree function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Shellapi.h; include Windows.h.
Library: Use Shell32.lib.
Unicode: Implemented only as Unicode.

See Also

Processes and Threads Overview, Process and Thread Functions, GetCommandLine, GlobalFree


ConvertThreadToFiber

The ConvertTheadToFiber function converts the current thread into a fiber. You must convert a thread into a fiber before you can schedule other fibers.

LPVOID ConvertThreadToFiber(
  LPVOID lpParameter  // fiber data for new fiber
);

Parameters

lpParameter
[in] Specifies a single variable that is passed to the fiber. The fiber can retrieve this value by using the GetFiberData macro.

Return Values

If the function succeeds, the return value is the address of the fiber.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Only fibers can execute other fibers. If a thread needs to execute a fiber, it must call ConvertThreadToFiber to create an area in which to save fiber state information. The thread is now the current fiber. The state information for this fiber includes the fiber data specified by lpParameter.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetFiberData


CreateFiber

The CreateFiber function allocates a fiber object, assigns it a stack, and sets up execution to begin at the specified start address, typically the fiber function. This function does not schedule the fiber.

LPVOID CreateFiber(
  DWORD dwStackSize,                    // initial stack size
  LPFIBER_START_ROUTINE lpStartAddress, // fiber function
  LPVOID lpParameter                    // fiber argument
);

Parameters

dwStackSize
[in] Specifies the size, in bytes, of the stack for the new fiber. The function fails if it cannot commit dwStackSize bytes. Note that the system increases the stack size dynamically, if necessary. For more information, see Thread Stack Size.
lpStartAddress
[in] Pointer to the application-defined function of type LPFIBER_START_ROUTINE to be executed by the fiber and represents the starting address of the fiber. Execution of the newly created fiber does not begin until another fiber calls the SwitchToFiber function with this address. For more information of the fiber callback function, see FiberProc.
lpParameter
[in] Specifies a single argument that is passed to the fiber. This value can be retrieved by the fiber using the GetFiberData macro.

Return Values

If the function succeeds, the return value is the address of the fiber.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

Before a thread can schedule a fiber using the SwitchToFiber function, it must call the ConvertThreadToFiber function so there is a fiber associated with the thread.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, ConvertThreadToFiber, FiberProc, GetFiberData, SwitchToFiber


CreateJobObject

The CreateJobObject function creates or opens a job object.

HANDLE CreateJobObject(
  LPSECURITY_ATTRIBUTES lpJobAttributes,  // SD
  LPCTSTR lpName                          // job name
);

Parameters

lpJobAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that specifies the security descriptor for the job object and determines whether child processes can inherit the returned handle. If lpJobAttributes is NULL, the job object gets a default security descriptor and the handle cannot be inherited.
lpName
[in] Pointer to a null-terminated string specifying the name of the job. The name is limited to MAX_PATH characters. Name comparison is case-sensitive.

If lpName is NULL, the job is created without a name.

If lpName matches the name of an existing event, semaphore, mutex, waitable timer, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 and later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Return Values

If the function succeeds, the return value is a handle to the job object. The handle has JOB_OBJECT_ALL_ACCESS access to the job object. If the object existed before the function call, the function returns a handle to the existing job object and GetLastError returns ERROR_ALREADY_EXISTS.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

When a job is created, its accounting information is initialized to zero, all limits are inactive, and there are no associated processes. To associate a process with a job, use the AssignProcessToJobObject function. To set limits for a job, use the SetInformationJobObject function. To query accounting information, use the QueryInformationJobObject function.

To close a job object handle, use the CloseHandle function. The job is destroyed when its last handle has been closed. If there are running processes still associated with the job when it is destroyed, they will continue to run even after the job is destroyed.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows 2000.

See Also

Processes and Threads Overview, Process and Thread Functions, AssignProcessToJobObject, CloseHandle, QueryInformationJobObject, SECURITY_ATTRIBUTES, SetInformationJobObject


CreateProcess

The CreateProcess function creates a new process and its primary thread. The new process runs the specified executable file.

To create a process that runs in a different security context, use the CreateProcessAsUser or CreateProcessWithLogonW function.

BOOL CreateProcess(
  LPCTSTR lpApplicationName,                 // name of executable module
  LPTSTR lpCommandLine,                      // command line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // handle inheritance option
  DWORD dwCreationFlags,                     // creation flags
  LPVOID lpEnvironment,                      // new environment block
  LPCTSTR lpCurrentDirectory,                // current directory name
  LPSTARTUPINFO lpStartupInfo,               // startup information
  LPPROCESS_INFORMATION lpProcessInformation // process information
);

Parameters

lpApplicationName
[in] Pointer to a null-terminated string that specifies the module to execute.

The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path.

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe

The specified module can be a Win32-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer.

Windows NT/2000 or later: If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module as well as its arguments. A 16-bit application is one that executes as a VDM or WOW process.

lpCommandLine
[in] Pointer to a null-terminated string that specifies the command line to execute. The system adds a null character to the command line, trimming the string if necessary, to indicate which file was actually used.

Windows NT/2000 or later: The Unicode version of this function, CreateProcessW, will fail if this parameter is a const string.

The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.

If both lpApplicationName and lpCommandLine are non-NULL, *lpApplicationName specifies the module to execute, and *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. C runtime processes can use the argc and argv arguments. Note that it is a common practice to repeat the module name as the first token in the command line.

If lpApplicationName is NULL, the first white-space – delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory for the parent process.
  3. Windows 95/98/Me: The Windows system directory. Use the GetSystemDirectory function to get the path of this directory.

    Windows NT/2000 or later: The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is System32.

  4. Windows NT/2000 or later: The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.
lpProcessAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpProcessAttributes is NULL, the handle cannot be inherited.

Windows NT/2000 or later: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new process. If lpProcessAttributes is NULL, the process gets a default security descriptor.

lpThreadAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.

Windows NT/2000 or later: The lpSecurityDescriptor member of the structure specifies a security descriptor for the main thread. If lpThreadAttributes is NULL, the thread gets a default security descriptor.

bInheritHandles
[in] Indicates whether the new process inherits handles from the calling process. If TRUE, each inheritable open handle in the calling process is inherited by the new process. Inherited handles have the same value and access privileges as the original handles.
dwCreationFlags
[in] Specifies additional flags that control the priority class and the creation of the process. The following creation flags can be specified in any combination, except as noted.
Value | Meaning
CREATE_BREAKAWAY_FROM_JOB Windows 2000 and later: The child processes of a process associated with a job are not associated with the job.

If the calling process is not associated with a job, this flag has no effect. If the calling process is associated with a job, the job must set the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit or CreateProcess will fail.

CREATE_DEFAULT_ERROR_MODE The new process does not inherit the error mode of the calling process. Instead, CreateProcess gives the new process the current default error mode. An application sets the current default error mode by calling SetErrorMode.

This flag is particularly useful for multi-threaded shell applications that run with hard errors disabled.

The default behavior for CreateProcess is for the new process to inherit the error mode of the caller. Setting this flag changes that default behavior.
CREATE_FORCEDOS | Windows NT/2000 or later: This flag is valid only when starting a 16-bit bound application. If set, the system will force the application to run as an MS-DOS-based application rather than as an OS/2-based application.
CREATE_NEW_CONSOLE | The new process has a new console, instead of inheriting the parent's console. This flag cannot be used with the DETACHED_PROCESS flag.
CREATE_NEW_PROCESS_GROUP | The new process is the root process of a new process group. The process group includes all processes that are descendants of this root process. The process identifier of the new process group is the same as the process identifier, which is returned in the lpProcessInformation parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+C or CTRL+BREAK signal to a group of console processes.
CREATE_NO_WINDOW | Windows NT/2000 or later: This flag is valid only when starting a console application. If set, the console application is run without a console window.
CREATE_PRESERVE_CODE_AUTHZ_LEVEL | Whistler: Allows the caller to execute a child process that bypasses the process restrictions that would normally be automatically applied to the process.
CREATE_SEPARATE_WOW_VDM | Windows NT/2000 or later: This flag is valid only when starting a 16-bit Windows-based application. If set, the new process runs in a private Virtual DOS Machine (VDM). By default, all 16-bit Windows-based applications run as threads in a single, shared VDM. The advantage of running separately is that a crash only terminates the single VDM; any other programs running in distinct VDMs continue to function normally. Also, 16-bit Windows-based applications that are run in separate VDMs have separate input queues. That means that if one application stops responding momentarily, applications in separate VDMs continue to receive input. The disadvantage of running separately is that it takes significantly more memory to do so. You should use this flag only if the user requests that 16-bit applications should run in them own VDM.
CREATE_SHARED_WOW_VDM | Windows NT/2000 or later: The flag is valid only when starting a 16-bit Windows-based application. If the DefaultSeparateVDM switch in the Windows section of WIN.INI is TRUE, this flag causes the CreateProcess function to override the switch and run the new process in the shared Virtual DOS Machine.
CREATE_SUSPENDED | The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.
CREATE_UNICODE_ENVIRONMENT | Indicates the format of the lpEnvironment parameter. If this flag is set, the environment block pointed to by lpEnvironment uses Unicode characters. Otherwise, the environment block uses ANSI characters.
DEBUG_PROCESS If this flag is set, the calling process is treated as a debugger, and the new process is debugged. The system notifies the debugger of all debug events that occur in the process being debugged.

If you create a process with this flag set, only the calling thread (the thread that called CreateProcess) can call the WaitForDebugEvent function.

Windows 95/98/Me: This flag is not valid if the new process is a 16-bit application.

DEBUG_ONLY_THIS_PROCESS | If this flag is not set and the calling process is being debugged, the new process becomes another process being debugged by the calling process's debugger. If the calling process is not a process being debugged, no debugging-related actions occur.
DETACHED_PROCESS | For console processes, the new process does not have access to the console of the parent process. The new process can call the AllocConsole function at a later time to create a new console. This flag cannot be used with the CREATE_NEW_CONSOLE flag.

The dwCreationFlags parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. If none of the following priority class flags is specified, the priority class defaults to NORMAL_PRIORITY_CLASS unless the priority class of the creating process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process. You can specify one of the following values.
Priority | Meaning
ABOVE_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority higher than NORMAL_PRIORITY_CLASS but lower than HIGH_PRIORITY_CLASS.
BELOW_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority higher than IDLE_PRIORITY_CLASS but lower than NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS | Indicates a process that performs time-critical tasks. The threads of a high-priority class process preempt the threads of normal-priority or idle-priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the load on the system. Use extreme care when using the high-priority class, because a CPU-bound application with a high-priority class can use nearly all available cycles.
IDLE_PRIORITY_CLASS | Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS | Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS | Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.

lpEnvironment
[in] Pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.

An environment block consists of a null-terminated block of null-terminated strings. Each string is in the form:

name=value

Because the equal sign is used as a separator, it must not be used in the name of an environment variable.

If an application provides an environment block, rather than passing NULL for this parameter, the current directory information of the system drives is not automatically propagated to the new process. For a discussion of this situation and how to handle it, see the following Remarks section.

An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, set the dwCreationFlags field's CREATE_UNICODE_ENVIRONMENT flag. Otherwise, do not set this flag.

Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.

lpCurrentDirectory
[in] Pointer to a null-terminated string that specifies the current drive and directory for the child process. The string must be a full path that includes a drive letter. If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
lpStartupInfo
[in] Pointer to a STARTUPINFO structure that specifies how the main window for the new process should appear.
lpProcessInformation
[out] Pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The CreateProcess function is used to run a new program. The WinExec and LoadModule functions are still available, but they are implemented as calls to CreateProcess.

In addition to creating a process, CreateProcess also creates a thread object. The thread is created with an initial stack whose size is described in the image header of the specified program's executable file. The thread begins execution at the image's entry point.

When created, the new process and the new thread handles receive full access rights. For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle to that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If access is denied, the requesting process cannot use the handle to gain access to the thread.

The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a thread identifier. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure.

When specifying an application name in the lpApplicationName or lpCommandLine strings, it doesn't matter whether the application name includes the file name extension, with one exception: an MS-DOS – based or Windows-based application whose file name extension is .com must include the .com extension.

Warning The first parameter, lpApplicationName, can be NULL, in which case the executable name must be the first white space-delimited string in lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".

CreateProcess(NULL, "C:\Program Files\MyApp", ...)

If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls CreateProcess using the Program Files directory will run this applicationinstead of the intended application.

To avoid this problem, do not pass NULL for lpApplicationName. Otherwise, use quotation marks around the executable path in lpCommandLine, as shown in the example below.

CreateProcess(NULL, "\"C:\Program Files\MyApp.exe\" -L -S", ...)

The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcess returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.

The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).

ExitProcess, ExitThread, CreateThread, CreateRemoteThread, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events at a time can happen in an address space, and the following restrictions apply.

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is finished for the process.
  • Only one thread at a time can be in a DLL initialization or detach routine.
  • The ExitProcess function does not return until there are no threads are in their DLL initialization or detach routines.

The created process remains in the system until all threads within the process have terminated and all handles to the process and any of its threads have been closed through calls to CloseHandle. The handles for both the process and the main thread must be closed through calls to CloseHandle. If these handles are not needed, it is best to close them immediately after the process is created.

When the last thread in a process terminates, the following events occur:

  • All objects opened by the process are implicitly closed.
  • The process's termination status (which is returned by GetExitCodeProcess) changes from its initial value of STILL_ACTIVE to the termination status of the last thread to terminate.
  • The thread object of the main thread is set to the signaled state, satisfying any threads that were waiting on the object.
  • The process object is set to the signaled state, satisfying any threads that were waiting on the object.

If the current directory on drive C is \MSVC\MFC, there is an environment variable called =C: whose value is C:\MSVC\MFC. As noted in the previous description of lpEnvironment, such current directory information for a system's drives does not automatically propagate to a new process when the CreateProcess function's lpEnvironment parameter is non-NULL. An application must manually pass the current directory information to the new process. To do so, the application must explicitly create the =X environment variable strings, get them into alphabetical order (because the system uses a sorted environment), and then put them into the environment block specified by lpEnvironment. Typically, they will go at the front of the environment block, due to the previously mentioned environment block sorting.

One way to obtain the current directory variable for a drive X is to call GetFullPathName ("X:",. .). That avoids an application having to scan the environment block. If the full path returned is X:\, there is no need to pass that value on as environment data, since the root directory is the default current directory for drive X of a new process.

The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object.

The current directory specified by the lpcurrentDirectory parameter is the current directory for the child process. The current directory specified in item 2 under the lpCommandLine parameter is the current directory for the parent process.

Note The name of the executable in the command line that the operating system provides to a process is not necessarily identical to that in the command line that the calling process gives to the CreateProcess function. The operating system may prepend a fully qualified path to an executable name that is provided without a fully qualified path.

Windows NT/2000 or later: When a process is created with CREATE_NEW_PROCESS_GROUP specified, an implicit call to SetConsoleCtrlHandler(NULL,TRUE) is made on behalf of the new process; this means that the new process has CTRL+C disabled. This lets good shells handle CTRL+C themselves, and selectively pass that signal on to sub-processes. CTRL+BREAK is not disabled, and may be used to interrupt the process/process group.

For example, see Creating Processes.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, AllocConsole, CloseHandle, CreateProcessAsUser, CreateProcessWithLogonW, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GenerateConsoleCtrlEvent, GetCommandLine, GetEnvironmentStrings, GetExitCodeProcess, GetFullPathName, GetStartupInfo, GetSystemDirectory, GetWindowsDirectory, LoadModule, OpenProcess, PROCESS_INFORMATION, ResumeThread, SECURITY_ATTRIBUTES, SetConsoleCtrlHandler, SetErrorMode, STARTUPINFO, TerminateProcess, WaitForInputIdle, WaitForDebugEvent, WinExec


CreateProcessAsUser

The CreateProcessAsUser function creates a new process and its primary thread. The new process then runs the specified executable file. The CreateProcessAsUser function is similar to the CreateProcess function, except that the new process runs in the security context of the user represented by the hToken parameter. By default, the new process is noninteractive, that is, it runs on a desktop that is not visible and cannot receive user input. Also, by default, the new process inherits the environment of the calling process, rather than the environment associated with the specified user.

The CreateProcessWithLogonW function is similar to CreateProcessAsUser, except that the caller does not need to call the LogonUser function to authenticate the user and get a token.

This function is also similar to the SHCreateProcessAsUserW function.

BOOL CreateProcessAsUser(
  HANDLE hToken,                             // handle to user token
  LPCTSTR lpApplicationName,                 // name of executable module
  LPTSTR lpCommandLine,                      // command-line string
  LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD
  LPSECURITY_ATTRIBUTES lpThreadAttributes,  // SD
  BOOL bInheritHandles,                      // inheritance option
  DWORD dwCreationFlags,                     // creation flags
  LPVOID lpEnvironment,                      // new environment block
  LPCTSTR lpCurrentDirectory,                // current directory name
  LPSTARTUPINFO lpStartupInfo,               // startup information
  LPPROCESS_INFORMATION lpProcessInformation // process information
);

Parameters

hToken
[in] Handle to a primary token that represents a user. The handle must have TOKEN_QUERY, TOKEN_DUPLICATE, and TOKEN_ASSIGN_PRIMARY access. For more information, see Access Rights for Access-Token Objects. The user represented by the token must have read and execute access to the application specified by the lpApplicationName or the lpCommandLine parameter.

If your process has the SE_TCB_NAME privilege, it can call the LogonUser function to get a primary token that represents the specified user.

Alternatively, you can call the DuplicateTokenEx function to convert an impersonation token into a primary token. This allows a server application that is impersonating a client to create a process that has the security context of the client.

Terminal Services: The process is run in the session specified in this token.

lpApplicationName
[in] Pointer to a null-terminated string that specifies the module to execute.

The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path.

This parameter can be NULL. In that case, the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe

The specified module can be a Win32-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer. If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module as well as its arguments. By default, all 16-bit Windows-based applications created by CreateProcessAsUser are run in a separate VDM (equivalent to CREATE_SEPARATE_WOW_VDM in CreateProcess).

lpCommandLine
[in] Pointer to a null-terminated string that specifies the command line to execute. The system adds a null character to the command line, trimming the string if necessary, to indicate which file was actually used.

Windows NT/2000 or later: The Unicode version of this function, CreateProcessAsUserW, will fail if this parameter is a const string.

The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.

If both lpApplicationName and lpCommandLine are non-NULL, *lpApplicationName specifies the module to execute, and *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. C runtime processes can use the argc and argv arguments. Note that it is a common practice to repeat the module name as the first token in the command line.

If lpApplicationName is NULL, the first white-space – delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is System32.
  4. The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.
lpProcessAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new process and determines whether child processes can inherit the returned handle. If lpProcessAttributes is NULL, the process gets a default security descriptor and the handle cannot be inherited.
lpThreadAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new process and determines whether child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the handle cannot be inherited.
bInheritHandles
[in] Indicates whether the new process inherits handles from the calling process. If TRUE, each inheritable open handle in the calling process is inherited by the new process. Inherited handles have the same value and access privileges as the original handles.
dwCreationFlags
[in] Specifies additional flags that control the priority class and the creation of the process. The following creation flags can be specified in any combination, except as noted.
Value | Meaning
CREATE_BREAKAWAY_FROM_JOB Windows 2000 and later: The child processes of a process associated with a job are not associated with the job.

If the calling process is not associated with a job, this flag has no effect. If the calling process is associated with a job, the job must set the JOB_OBJECT_LIMIT_BREAKAWAY_OK limit or CreateProcess will fail.

CREATE_DEFAULT_ERROR_MODE The new process does not inherit the error mode of the calling process. Instead, CreateProcessAsUser gives the new process the current default error mode. An application sets the current default error mode by calling SetErrorMode.

This flag is particularly useful for multi-threaded shell applications that run with hard errors disabled.

The default behavior for CreateProcessAsUser is for the new process to inherit the error mode of the caller. Setting this flag changes that default behavior.
CREATE_NEW_CONSOLE | The new process has a new console, instead of inheriting the parent's console. This flag cannot be used with the DETACHED_PROCESS flag.
CREATE_NEW_PROCESS_GROUP | The new process is the root process of a new process group. The process group includes all processes that are descendants of this root process. The process identifier of the new process group is the same as the process identifier, which is returned in the lpProcessInformation parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+C or CTRL+BREAK signal to a group of console processes.
CREATE_SUSPENDED | The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.
CREATE_UNICODE_ENVIRONMENT | Indicates the format of the lpEnvironment parameter. If this flag is set, the environment block pointed to by lpEnvironment uses Unicode characters. Otherwise, the environment block uses ANSI characters.
DEBUG_ONLY_THIS_PROCESS | If this flag is not set and the calling process is being debugged, the new process becomes another process being debugged by the calling process's debugger. If the calling process is not a process being debugged, no debugging-related actions occur.
DEBUG_PROCESS | If this flag is set, the calling process is treated as a debugger, and the new process is debugged. The system notifies the debugger of all debug events that occur in the process being debugged.
DETACHED_PROCESS | For console processes, the new process does not have access to the console of the parent process. The new process can call the AllocConsole function later to create a new console. This flag cannot be used with the CREATE_NEW_CONSOLE flag.

The dwCreationFlags parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. If none of the following priority class flags is specified, the priority class is NORMAL_PRIORITY_CLASS by default unless the priority class of the creating process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process. One of the following flags can be specified.
Priority | Meaning
ABOVE_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority higher than NORMAL_PRIORITY_CLASS but lower than HIGH_PRIORITY_CLASS.
BELOW_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority higher than IDLE_PRIORITY_CLASS but lower than NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS | Indicates a process that performs time-critical tasks. The threads of a high-priority class process preempt the threads of normal-priority or idle-priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a CPU-bound application with a high-priority class can use nearly all available cycles.
IDLE_PRIORITY_CLASS | Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS | Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS | Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.

lpEnvironment
[in] Pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.

If an application provides an environment block, rather than passing NULL for this parameter, the current directory information of the system drives is not automatically propagated to the new process. For a discussion of this situation and how to handle it, see the following Remarks section.

An environment block can contain either Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, set the dwCreationFlags field's CREATE_UNICODE_ENVIRONMENT flag. Otherwise, do not set this flag.

Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.

To retrieve a copy of the environment block for a given user, use the CreateEnvironmentBlock function.

lpCurrentDirectory
[in] Pointer to a null-terminated string that specifies the current drive and directory for the new process. The string must be a full path that includes a drive letter. If this parameter is NULL, the new process will have the same current drive and directory as the calling process. (This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
lpStartupInfo
[in] Pointer to a STARTUPINFO structure that specifies how the main window for the new process should appear.
lpProcessInformation
[out] Pointer to a PROCESS_INFORMATION structure that receives identification information about the new process.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Typically, the process that calls the CreateProcessAsUser function must have the SE_ASSIGNPRIMARYTOKEN_NAME and SE_INCREASE_QUOTA_NAME privileges. However, if hToken is a restricted version of the caller's primary token, the SE_ASSIGNPRIMARYTOKEN_NAME privilege is not required. If the necessary privileges are not already enabled, CreateProcessAsUser enables them for the duration of the call.

CreateProcessAsUser must be able to open the primary token of the calling process for TOKEN_DUPLICATE and TOKEN_IMPERSONATE access.

By default, CreateProcessAsUser creates the new process on a noninteractive window station with a desktop that is not visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default interactive window station and desktop, "winsta0\default", in the lpDesktop member of the STARTUPINFO structure. In addition, before calling CreateProcessAsUser, you must change the discretionary access control list (DACL) of both the default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the user or the logon session represented by the hToken parameter.

CreateProcessAsUser does not load the specified user's profile into the HKEY_USERS registry key. This means that access to information in the HKEY_CURRENT_USER registry key may not produce results consistent with a normal interactive logon. It is your responsibility to load the user's registry hive into HKEY_USERS with the LoadUserProfile function before calling CreateProcessAsUser.

If the lpEnvironment parameter is NULL, the new process inherits the environment of the calling process. CreateProcessAsUser does not automatically modify the environment block to include environment variables specific to the user represented by hToken. For example, the USERNAME and USERDOMAIN variables are inherited from the calling process if lpEnvironment is NULL. It is your responsibility to prepare the environment block for the new process and specify it in lpEnvironment.

CreateProcessAsUser allows you to access the specified directory and executable image in the security context of the caller or the target user. By default, CreateProcessAsUser accesses the directory and executable image in the security context of the caller. In this case, if the caller does not have access to the directory and executable image, the function fails. To access the directory and executable image using the security context of the target user, specify hToken in a call to the ImpersonateLoggedOnUser function before calling CreateProcessAsUser.

When created, the new process and the new thread handles receive full access rights (PROCESS_ALL_ACCESS and THREAD_ALL_ACCESS). For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle of that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If access is denied, the requesting process is not able to use the handle to gain access to the process or thread.

If the lpProcessAttributes parameter is NULL, the default security descriptor for the user referenced in the hToken parameter will be used. This security descriptor may not allow access for the caller, in which case the process may not be opened again once it is run. The handle returned in the PROCESS_INFORMATION structure is valid and will continue to have full access rights. This is also true for thread attributes.

Handles in PROCESS_INFORMATION must be closed with CloseHandle when they are no longer needed.

The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a thread identifier. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in the PROCESS_INFORMATION structure.

When specifying an application name in the lpApplicationName or lpCommandLine strings, it doesn't matter whether the application name includes the file name extension, with one exception: an MS-DOS – based or Windows-based application whose file name extension is .com must include the .com extension.

Warning The parameter lpApplicationName can be NULL, in which case the executable name must be the first white space-delimited string in lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".

CreateProcess(NULL, "C:\Program Files\MyApp", ...)

If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls CreateProcess using the Program Files directory will run this application instead of the intended application.

To avoid this problem, do not pass NULL for lpApplicationName. Otherwise, use quotation marks around the executable path in lpCommandLine, as shown in the example below.

CreateProcess(NULL, "\"C:\Program Files\MyApp.exe\" -L -S", ...)

The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcessAsUser returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.

The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).

ExitProcess, ExitThread, CreateThread, CreateRemoteThread, and a process that is starting (as the result of a call by CreateProcessAsUser) are serialized between each other within a process. Only one of these events can happen at a time, and the following restrictions apply:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is finished for the process.
  • Only one thread at a time can be in a DLL initialization or detach routine.
  • The ExitProcess function does not return until there are no threads executing DLL initialization or detach routines.

For example, see Starting an Interactive Client Process.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, CreateEnvironmentBlock, CreateProcess, CreateProcessWithLogonW, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GetEnvironmentStrings, GetExitCodeProcess, GetStartupInfo, ImpersonateLoggedOnUser, PROCESS_INFORMATION, SECURITY_ATTRIBUTES, SetErrorMode, SHCreateProcessAsUserW, STARTUPINFO, WaitForInputIdle


CreateProcessWithLogonW

The CreateProcessWithLogonW function creates a new process and its primary thread. The new process then runs the specified executable file in the security context of the specified credentials (user, domain, and password). It can optionally load the user profile of the specified user.

The CreateProcessWithLogonW function is similar to the CreateProcessAsUser function, except that the caller does not need to call the LogonUser function to authenticate the user and get a token.

BOOL CreateProcessWithLogonW(
  LPCWSTR lpUsername,                 // user's name
  LPCWSTR lpDomain,                   // user's domain
  LPCWSTR lpPassword,                 // user's password
  DWORD dwLogonFlags,                 // logon option
  LPCWSTR lpApplicationName,          // executable module name
  LPWSTR lpCommandLine,               // command-line string
  DWORD dwCreationFlags,              // creation flags
  LPVOID lpEnvironment,               // new environment block
  LPCWSTR lpCurrentDirectory,         // current directory name
  LPSTARTUPINFOW lpStartupInfo,       // startup information
  LPPROCESS_INFORMATION lpProcessInfo // process information
);

Parameters

lpUsername
[in] Pointer to a null-terminated string that specifies the name of the user. This is the name of the user account to log on to. If you use the format user@DNS_domain_name, the lpDomain parameter should be NULL.

The user account must have Log On Locally permission on the local computer. This permission is granted to all users on workstations and servers, but only to administrators on domain controllers.

lpDomain
[in] Pointer to a null-terminated string that specifies the name of the domain or server whose account database contains the lpUsername account.

If this parameter is NULL, CreateProcessWithLogonW attempts to validate the account using the local account database. If CreateProcessWithLogonW cannot find the account in the local account database, its trusted domains search their account databases until a match is found. Note that this parameter cannot be NULL unless you specify the user name in UPN format.

lpPassword
[in] Pointer to a null-terminated string that specifies the clear-text password for the lpUsername account.
dwLogonFlags
[in] Specifies the logon option. This parameter can be one of the following values.
Value | Meaning
LOGON_WITH_PROFILE | Log on, then load the user's profile. Loading the profile can be time-consuming, so it is best to use this value only if you must access the user's profile information.
LOGON_NETCREDENTIALS_ONLY Log on, but use the specified credentials on the network only. The new process uses the same token as the caller, but the system creates a new logon session within LSA, and the process uses the specified credentials as the default credentials.

This value can be used to create a process that uses a different set of credentials locally than it does remotely. This is useful in inter-domain scenarios where there is no trust relationship.

lpApplicationName
[in] Pointer to a null-terminated string that specifies the module to execute.

The string can specify the full path and file name of the module to execute or it can specify a partial name. In the case of a partial name, the function uses the current drive and current directory to complete the specification. The function will not use the search path.

This parameter can be NULL. In that case, the module name must be the first white space-delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; otherwise, the file name is ambiguous. For example, consider the string "c:\program files\sub dir\program name". This string can be interpreted in a number of ways. The system tries to interpret the possibilities in the following order:

c:\program.exe files\sub dir\program name
c:\program files\sub.exe dir\program name
c:\program files\sub dir\program.exe name
c:\program files\sub dir\program name.exe

The specified module can be a Win32-based application. It can be some other type of module (for example, MS-DOS or OS/2) if the appropriate subsystem is available on the local computer. If the executable module is a 16-bit application, lpApplicationName should be NULL, and the string pointed to by lpCommandLine should specify the executable module as well as its arguments. A 16-bit application is one that executes as a VDM or WOW process.

lpCommandLine
[in] Pointer to a null-terminated string that specifies the command line to execute. The system adds a null character to the command line, trimming the string if necessary, to indicate which file was actually used.

Windows NT/2000 or later: The Unicode version of this function, CreateProcessWithLogonW, will fail if this parameter is a const string.

The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.

If both lpApplicationName and lpCommandLine are non-NULL, *lpApplicationName specifies the module to execute, and *lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. C runtime processes can use the argc and argv arguments. Note that it is a common practice to repeat the module name as the first token in the command line.

If lpApplicationName is NULL, the first white-space – delimited token of the command line specifies the module name. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin (see the explanation for the lpApplicationName parameter). If the file name does not contain an extension, .exe is appended. If the file name ends in a period (.) with no extension, or if the file name contains a path, .exe is not appended. If the file name does not contain a directory path, the system searches for the executable file in the following sequence:

  1. The directory from which the application loaded.
  2. The current directory.
  3. The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory. The name of this directory is System32.
  4. The 16-bit Windows system directory. There is no Win32 function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
  6. The directories that are listed in the PATH environment variable.
dwCreationFlags
[in] Specifies how the process is created. The CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE, and CREATE_NEW_PROCESS_GROUP flags are enabled by default. You can specifiy additional flags as noted.
Value | Meaning
CREATE_DEFAULT_ERROR_MODE The new process does not inherit the error mode of the calling process. Instead, CreateProcessWithLogonW gives the new process the current default error mode. An application sets the current default error mode by calling SetErrorMode.

This flag is enabled by default.

CREATE_NEW_CONSOLE The new process has a new console, instead of inheriting the parent's console. This flag cannot be used with the DETACHED_PROCESS flag.

This flag is enabled by default.

CREATE_NEW_PROCESS_GROUP The new process is the root process of a new process group. The process group includes all processes that are descendants of this root process. The process identifier of the new process group is the same as the process identifier, which is returned in the lpProcessInfo parameter. Process groups are used by the GenerateConsoleCtrlEvent function to enable sending a CTRL+C or CTRL+BREAK signal to a group of console processes.

This flag is enabled by default.

CREATE_SEPARATE_WOW_VDM | This flag is only valid starting a 16-bit Windows-based application. If set, the new process runs in a private Virtual DOS Machine (VDM). By default, all 16-bit Windows-based applications run in a single, shared VDM. The advantage of running separately is that a crash only terminates the single VDM; any other programs running in distinct VDMs continue to function normally. Also, 16-bit Windows-based applications that run in separate VDMs have separate input queues. That means that if one application stops responding momentarily, applications in separate VDMs continue to receive input.
CREATE_SUSPENDED | The primary thread of the new process is created in a suspended state, and does not run until the ResumeThread function is called.
CREATE_UNICODE_ENVIRONMENT | Indicates the format of the lpEnvironment parameter. If this flag is set, the environment block pointed to by lpEnvironment uses Unicode characters. Otherwise, the environment block uses ANSI characters.

The dwCreationFlags parameter also controls the new process's priority class, which is used to determine the scheduling priorities of the process's threads. If none of the following priority class flags is specified, the priority class is NORMAL_PRIORITY_CLASS by default unless the priority class of the creating process is IDLE_PRIORITY_CLASS or BELOW_NORMAL_PRIORITY_CLASS. In this case, the child process receives the default priority class of the calling process. One of the following flags can be specified.
Priority | Meaning
ABOVE_NORMAL_PRIORITY_CLASS | Windows 2000 or later: Indicates a process that has priority higher than NORMAL_PRIORITY_CLASS but lower than HIGH_PRIORITY_CLASS.
BELOW_NORMAL_PRIORITY_CLASS | Windows 2000 or later: Indicates a process that has priority higher than IDLE_PRIORITY_CLASS but lower than NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS | Indicates a process that performs time-critical tasks. The threads of a high-priority class process preempt the threads of normal-priority or idle-priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a CPU-bound application with a high-priority class can use nearly all available cycles.
IDLE_PRIORITY_CLASS | Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS | Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS | Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.

lpEnvironment
[in] Pointer to an environment block for the new process. If this parameter is NULL, the new process uses the environment of the calling process.

An environment block consists of a null-terminated block of null-terminated strings. Each string is in the form:

name=value

Because the equal sign is used as a separator, it must not be used in the name of an environment variable.

If an application provides an environment block, rather than passing NULL for this parameter, the current directory information of the system drives is not automatically propagated to the new process. For a discussion of this situation and how to handle it, see the following Remarks section.

An environment block can contain Unicode or ANSI characters. If the environment block pointed to by lpEnvironment contains Unicode characters, set the dwCreationFlags parameter's CREATE_UNICODE_ENVIRONMENT flag. Otherwise, do not set this flag.

Note that an ANSI environment block is terminated by two zero bytes: one for the last string, one more to terminate the block. A Unicode environment block is terminated by four zero bytes: two for the last string, two more to terminate the block.

To retrieve a copy of the environment block for a given user, use the CreateEnvironmentBlock function.

lpCurrentDirectory
[in] Pointer to a null-terminated string that specifies the current drive and directory for the new process. The string must be a full path that includes a drive letter. If this parameter is NULL, the new process has the same current drive as the system service that creates the process. (This feature is provided primarily for shells that need to start an application and specify its initial drive and working directory.)
lpStartupInfo
[in] Pointer to a STARTUPINFO structure that specifies how the main window for the new process should appear.
lpProcessInfo
[out] Pointer to a PROCESS_INFORMATION structure that receives identification information for the new process, including a handle to the process.

Handles in PROCESS_INFORMATION must be closed with the CloseHandle function when they are no longer needed.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

By default, CreateProcessWithLogonW creates the new process on a noninteractive window station with a desktop that is not visible and cannot receive user input. To enable user interaction with the new process, you must specify the name of the default interactive window station and desktop, "winsta0\default", in the lpDesktop member of the STARTUPINFO structure. In addition, before calling CreateProcessWithLogonW, you must change the discretionary access control list (DACL) of both the default interactive window station and the default desktop. The DACLs for the window station and desktop must grant access to the user represented by the lpUsername parameter.

By default, CreateProcessWithLogonW does not load the specified user's profile into the HKEY_USERS registry key. This means that access to information in the HKEY_CURRENT_USER registry key may not produce results consistent with a normal interactive logon. It is your responsibility to load the user's registry hive into HKEY_USERS before calling CreateProcessWithLogonW, using either LOGON_WITH_PROFILE, or by calling the LoadUserProfile function.

If the lpEnvironment parameter is NULL, the new process inherits the environment of the calling process. CreateProcessWithLogonW does not automatically modify the environment block to include environment variables specific to the user. For example, the USERNAME and USERDOMAIN variables are inherited from the calling process if lpEnvironment is NULL. It is your responsibility to prepare the environment block for the new process and specify it in lpEnvironment.

When created, the new process and the new thread handles receive full access rights (PROCESS_ALL_ACCESS and THREAD_ALL_ACCESS). For either handle, if a security descriptor is not provided, the handle can be used in any function that requires an object handle of that type. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If access is denied, the requesting process cannot use the handle to gain access to the process or thread.

To retrieve a security token, pass the process handle in the PROCESS_INFORMATION structure to the OpenProcessToken function.

If the lpProcessAttributes parameter is NULL, the function uses the default security descriptor for the user. This security descriptor may not allow access for the caller, in which case the process may not be opened again after it is run. The process handle is valid and will continue to have complete access. This is also true for thread attributes.

The process is assigned a process identifier. The identifier is valid until the process terminates. It can be used to identify the process, or specified in the OpenProcess function to open a handle to the process. The initial thread in the process is also assigned a thread identifier. It can be specified in the OpenThread function to open a handle to the thread. The identifier is valid until the thread terminates and can be used to uniquely identify the thread within the system. These identifiers are returned in PROCESS_INFORMATION.

When specifying an application name in the lpApplicationName or lpCommandLine strings, it doesn't matter whether the application name includes the file name extension, with one exception: an MS-DOS – based or Windows-based application whose file name extension is .com must include the .com extension.

Warning The parameter lpApplicationName can be NULL, in which case the executable name must be the first white space-delimited string in lpCommandLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".

CreateProcess(NULL, "C:\Program Files\MyApp", ...)

If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls CreateProcess using the Program Files directory will run this application instead of the intended application.

To avoid this problem, do not pass NULL for lpApplicationName. Otherwise, use quotation marks around the executable path in lpCommandLine, as shown in the example below.

CreateProcess(NULL, "\"C:\Program Files\MyApp.exe\" -L -S", ...)

The calling thread can use the WaitForInputIdle function to wait until the new process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronization between parent and child processes, because CreateProcessWithLogonW returns without waiting for the new process to finish its initialization. For example, the creating process would use WaitForInputIdle before trying to find a window associated with the new process.

The preferred way to shut down a process is by using the ExitProcess function, because this function sends notification of approaching termination to all DLLs attached to the process. Other means of shutting down a process do not notify the attached DLLs. Note that when a thread calls ExitProcess, other threads of the process are terminated without an opportunity to execute any additional code (including the thread termination code of attached DLLs).

The ExitProcess, ExitThread, CreateThread, and CreateRemoteThread functions, and processes that are starting (as the result of a call by CreateProcessWithLogonW) are serialized within a process. Only one of these events can happen at a time, and the following restrictions apply:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is finished for the process.
  • Only one thread at a time can be in a DLL initialization or detach routine.
  • The ExitProcess function does not return until there are no threads executing DLL initialization or detach routines.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented only as Unicode.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, CreateEnvironmentBlock, CreateProcessAsUser, CreateRemoteThread, CreateThread, ExitProcess, ExitThread, GetExitCodeProcess, OpenProcess, OpenThread, PROCESS_INFORMATION, SetErrorMode, STARTUPINFO, WaitForInputIdle


CreateRemoteThread

The CreateRemoteThread function creates a thread that runs in the virtual address space of another process.

HANDLE CreateRemoteThread(
  HANDLE hProcess,                          // handle to process
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
  DWORD dwStackSize,                        // initial stack size
  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
  LPVOID lpParameter,                       // thread argument
  DWORD dwCreationFlags,                    // creation option
  LPDWORD lpThreadId                        // thread identifier
);

Parameters

hProcess
[in] Handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights. For more information, see Process Security and Access Rights.
lpThreadAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new thread and determines whether child processes can inherit the returned handle. If lpThreadAttributes is NULL, the thread gets a default security descriptor and the handle cannot be inherited.
dwStackSize
[in] Specifies the initial commit size of the stack, in bytes. The system rounds this value to the nearest page. For more information, see Thread Stack Size.
lpStartAddress
[in] Pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the starting address of the thread in the remote process. The function must exist in the remote process. For more information on the thread function, see ThreadProc.
lpParameter
[in] Specifies a single value passed to the thread function.
dwCreationFlags
[in] Specifies additional flags that control the creation of the thread. If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state and will not run until the ResumeThread function is called. If this value is zero, the thread runs immediately after creation.
lpThreadId
[out] Pointer to a variable that receives the thread identifier.

If this parameter is NULL, the thread identifier is not returned.

Return Values

If the function succeeds, the return value is a handle to the new thread.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Note that CreateRemoteThread may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).

Remarks

The CreateRemoteThread function causes a new thread of execution to begin in the address space of the specified process. The thread has access to all objects opened by the process.

The new thread handle is created with full access to the new thread. If a security descriptor is not provided, the handle may be used in any function that requires a thread object handle. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process cannot use the handle to gain access to the thread.

The thread is created with a thread priority of THREAD_PRIORITY_NORMAL. Use the GetThreadPriority and SetThreadPriority functions to get and set the priority value of a thread.

When a thread terminates, the thread object attains a signaled state, satisfying any threads that were waiting for the object.

The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a CreateProcess call) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.
  • Only one thread in a process can be in a DLL initialization or detach routine at a time.
  • ExitProcess does not return until no threads are in their DLL initialization or detach routines.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, CreateProcess, CreateThread, ExitProcess, ExitThread, GetThreadPriority, ResumeThread, SECURITY_ATTRIBUTES, SetThreadPriority, ThreadProc


CreateThread

The CreateThread function creates a thread to execute within the virtual address space of the calling process.

To create a thread that runs in the virtual address space of another process, use the CreateRemoteThread function.

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
  DWORD dwStackSize,                        // initial stack size
  LPTHREAD_START_ROUTINE lpStartAddress,    // thread function
  LPVOID lpParameter,                       // thread argument
  DWORD dwCreationFlags,                    // creation option
  LPDWORD lpThreadId                        // thread identifier
);

Parameters

lpThreadAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpThreadAttributes is NULL, the handle cannot be inherited.

Windows NT/2000 or later: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new thread. If lpThreadAttributes is NULL, the thread gets a default security descriptor.

dwStackSize
[in] Specifies the initial commit size of the stack, in bytes. The system rounds this value to the nearest page. For more information, see Thread Stack Size.
lpStartAddress
[in] Pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the starting address of the thread. For more information on the thread function, see ThreadProc.
lpParameter
[in] Specifies a single parameter value passed to the thread.
dwCreationFlags
[in] Specifies additional flags that control the creation of the thread. If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state, and will not run until the ResumeThread function is called. If this value is zero, the thread runs immediately after creation. At this time, no other values are supported.
lpThreadId
[out] Pointer to a variable that receives the thread identifier.

Windows NT/2000 or later: If this parameter is NULL, the thread identifier is not returned.

Windows 95/98/Me: This parameter may not be NULL.

Return Values

If the function succeeds, the return value is a handle to the new thread.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Note that CreateThread may succeed even if lpStartAddress points to data, code, or is not accessible. If the start address is invalid when the thread runs, an exception occurs, and the thread terminates. Thread termination due to a invalid start address is handled as an error exit for the thread's process. This behavior is similar to the asynchronous nature of CreateProcess, where the process is created even if it refers to invalid or missing dynamic-link libraries (DLLs).

Windows 95/98/Me: CreateThread succeeds only when it is called in the context of a 32-bit program. A 32-bit DLL cannot create an additional thread when that DLL is being called by a 16-bit program.

Remarks

The number of threads a process can create is limited by the available virtual memory. By default, every thread has one megabyte of stack space. Therefore, you can create at most 2028 threads. If you reduce the default stack size, you can create more threads. However, your application will have better performance if you create one thread per processor and build queues of requests for which the application maintains the context information. A thread would process all requests in a queue before processing requests in the next queue.

The new thread handle is created with THREAD_ALL_ACCESS to the new thread. If a security descriptor is not provided, the handle can be used in any function that requires a thread object handle. When a security descriptor is provided, an access check is performed on all subsequent uses of the handle before access is granted. If the access check denies access, the requesting process cannot use the handle to gain access to the thread. If the thread impersonates a client, then calls CreateThread with a NULL security descriptor, the thread object created has a default security descriptor which allows access only to the impersonation token's TokenDefaultDacl owner or members. For more information, see Thread Security and Access Rights.

The thread execution begins at the function specified by the lpStartAddress parameter. If this function returns, the DWORD return value is used to terminate the thread in an implicit call to the ExitThread function. Use the GetExitCodeThread function to get the thread's return value.

The thread is created with a thread priority of THREAD_PRIORITY_NORMAL. Use the GetThreadPriority and SetThreadPriority functions to get and set the priority value of a thread.

When a thread terminates, the thread object attains a signaled state, satisfying any threads that were waiting on the object.

The thread object remains in the system until the thread has terminated and all handles to it have been closed through a call to CloseHandle.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means that the following restrictions hold:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.
  • Only one thread in a process can be in a DLL initialization or detach routine at a time.
  • ExitProcess does not return until no threads are in their DLL initialization or detach routines.

A thread that uses functions from the C run-time libraries should use the beginthread and endthread C run-time functions for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when ExitThread is called.

For example, see Creating Threads.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, CreateProcess, CreateRemoteThread, ExitProcess, ExitThread, GetExitCodeThread, GetThreadPriority, ResumeThread, SetThreadPriority, SECURITY_ATTRIBUTES, ThreadProc


DeleteFiber

The DeleteFiber function deletes an existing fiber.

VOID DeleteFiber(
  LPVOID lpFiber   // pointer to the fiber to delete
);

Parameters

lpFiber
[in] Specifies the address of the fiber to delete.

Return Values

This function does not return a value.

Remarks

The DeleteFiber function deletes all data associated with the fiber. This data includes the stack, a subset of the registers, and the fiber data. If the currently running fiber calls DeleteFiber, the ExitThread function is called and the thread terminates. If the currently running fiber is deleted by another thread, the thread associated with the fiber is likely to terminate abnormally because the fiber stack has been freed.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, ExitThread


ExitProcess

The ExitProcess function ends a process and all its threads.

VOID ExitProcess(
  UINT uExitCode   // exit code for all threads
);

Parameters

uExitCode
[in] Specifies the exit code for the process, and for all threads that are terminated as a result of this call. Use the GetExitCodeProcess function to retrieve the process's exit value. Use the GetExitCodeThread function to retrieve a thread's exit value.

Return Values

This function does not return a value.

Remarks

ExitProcess is the preferred method of ending a process. This function provides a clean process shutdown. This includes calling the entry-point function of all attached dynamic-link libraries (DLLs) with a value indicating that the process is detaching from the DLL. If a process terminates by calling TerminateProcess, the DLLs that the process is attached to are not notified of the process termination.

After all attached DLLs have executed any process termination value, this function terminates the current process.

Terminating a process causes the following:

  1. All of the object handles opened by the process are closed.
  2. All of the threads in the process terminate their execution.
  3. The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.
  4. The states of all threads of the process become signaled, satisfying any threads that had been waiting for the threads to terminate.
  5. The termination status of the process changes from STILL_ACTIVE to the exit value of the process.

Terminating a process does not cause child processes to be terminated.

Terminating a process does not necessarily remove the process object from the operating system. A process object is deleted when the last handle to the process is closed.

Warning Calling ExitProcess in a DLL can lead to unexpected application or system errors. Be sure to call ExitProcess from a DLL only if you know which applications or system components will load the DLL and that it is safe to call ExitProcess in this context.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.
  • Only one thread in a process can be in a DLL initialization or detach routine at a time.
  • If any process is in its DLL initialization or detach routine, ExitProcess does not return.

For an example, see Creating a Child Process with Redirected Input and Output.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, CreateRemoteThread, CreateThread, ExitThread, GetExitCodeProcess, GetExitCodeThread, OpenProcess, TerminateProcess


ExitThread

The ExitThread function ends a thread.

VOID ExitThread(
  DWORD dwExitCode   // exit code for this thread
);

Parameters

dwExitCode
[in] Specifies the exit code for the calling thread. Use the GetExitCodeThread function to retrieve a thread's exit code.

Return Values

This function does not return a value.

Remarks

ExitThread is the preferred method of exiting a thread. When this function is called (either explicitly or by returning from a thread procedure), the current thread's stack is deallocated and the thread terminates. The entry-point function of all attached dynamic-link libraries (DLLs) is invoked with a value indicating that the thread is detaching from the DLL.

If the thread is the last thread in the process when this function is called, the thread's process is also terminated.

The state of the thread object becomes signaled, releasing any other threads that had been waiting for the thread to terminate. The thread's termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.

Terminating a thread does not necessarily remove the thread object from the operating system. A thread object is deleted when the last handle to the thread is closed.

The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a CreateProcess call) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

  • During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.
  • Only one thread in a process can be in a DLL initialization or detach routine at a time.
  • ExitProcess does not return until no threads are in their DLL initialization or detach routines.

A thread that uses functions from the C run-time libraries should use the _beginthread and _endthread C run-time functions for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when ExitThread is called.

For example, see Using Event Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, CreateRemoteThread, CreateThread, ExitProcess, FreeLibraryAndExitThread, GetExitCodeThread, OpenThread, TerminateThread


FiberProc

The FiberProc function is an application-defined function used with the CreateFiber function. It serves as the starting address for a fiber. The LPFIBER_START_ROUTINE type defines a pointer to this callback function. FiberProc is a placeholder for the application-defined function name.

VOID CALLBACK FiberProc(
  PVOID lpParameter   // fiber data
);

Parameters

lpParameter
[in] Receives the fiber data passed to the function using the lpParameter parameter of the CreateFiber function.

Return Values

This function does not return a value.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateFiber


FreeEnvironmentStrings

The FreeEnvironmentStrings function frees a block of environment strings.

BOOL FreeEnvironmentStrings(
  LPTSTR lpszEnvironmentBlock  // environment strings
);

Parameters

lpszEnvironmentBlock
[in] Pointer to a block of environment strings. The pointer to the block must be obtained by calling the GetEnvironmentStrings function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero To get extended error information, call GetLastError.

Remarks

When GetEnvironmentStrings is called, it allocates memory for a block of environment strings. When the block is no longer needed, it should be freed by calling FreeEnvironmentStrings.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, GetEnvironmentStrings


GetCommandLine

The GetCommandLine function retrieves the command-line string for the current process.

LPTSTR GetCommandLine(VOID);

Parameters

This function has no parameters.

Return Values

The return value is a pointer to the command-line string for the current process.

Remarks

ANSI console processes written in C can use the argc and argv arguments of the main function to access the command-line arguments. ANSI GUI applications can use the lpCmdLine parameter of the WinMain function to access the command-line string, excluding the program name. The reason that main and WinMain cannot return Unicode strings is that argc, argv, and lpCmdLine use the LPSTR data type for parameters, not the LPTSTR data type. The GetCommandLine function can be used to access Unicode strings, because it uses the LPTSTR data type.

To convert the command line to an argv style array of strings, call the CommandLineToArgvW function.

Note The name of the executable in the command line that the operating system provides to a process is not necessarily identical to that in the command line that the calling process gives to the CreateProcess function. The operating system may prepend a fully qualified path to an executable name that is provided without a fully qualified path.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on all platforms.

See Also

Processes and Threads Overview, Process and Thread Functions, CommandLineToArgvW, CreateProcess, WinMain


GetCurrentProcess

The GetCurrentProcess function retrieves a pseudo handle for the current process.

HANDLE GetCurrentProcess(VOID);

Parameters

This function has no parameters.

Return Values

The return value is a pseudo handle to the current process.

Remarks

A pseudo handle is a special constant that is interpreted as the current process handle. The calling process can use this handle to specify its own process whenever a process handle is required. Pseudo handles are not inherited by child processes.

This handle has the maximum possible access to the process object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is PROCESS_ALL_ACCESS. For more information, see Process Security and Access Rights.

A process can create a "real" handle to itself that is valid in the context of other processes, or that can be inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function. A process can also use the OpenProcess function to open a real handle to itself.

The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with a pseudo handle has no effect. If the pseudo handle is duplicated by DuplicateHandle, the duplicate handle must be closed.

For example, see Creating a Child Process with Redirected Input and Output.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, DuplicateHandle, GetCurrentProcessId, GetCurrentThread, OpenProcess


GetCurrentProcessId

The GetCurrentProcessId function retrieves the process identifier of the calling process.

DWORD GetCurrentProcessId(VOID);

Parameters

This function has no parameters.

Return Values

The return value is the process identifier of the calling process.

Remarks

Until the process terminates, the process identifier uniquely identifies the process throughout the system.

MAPI: For more information, see Syntax and Limitations for Win32 Functions Useful in MAPI Development.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetCurrentProcess, OpenProcess


GetCurrentThread

The GetCurrentThread function retrieves a pseudo handle for the current thread.

HANDLE GetCurrentThread(VOID);

Parameters

This function has no parameters.

Return Values

The return value is a pseudo handle for the current thread.

Remarks

A pseudo handle is a special constant that is interpreted as the current thread handle. The calling thread can use this handle to specify itself whenever a thread handle is required. Pseudo handles are not inherited by child processes.

This handle has the maximum possible access to the thread object. For systems that support security descriptors, this is the maximum access allowed by the security descriptor for the calling process. For systems that do not support security descriptors, this is THREAD_ALL_ACCESS.

The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function.

The pseudo handle need not be closed when it is no longer needed. Calling the CloseHandle function with this handle has no effect. If the pseudo handle is duplicated by DuplicateHandle, the duplicate handle must be closed.

For example, see Checking Client Access.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, DuplicateHandle, GetCurrentProcess, GetCurrentThreadId, OpenThread


GetCurrentThreadId

The GetCurrentThreadId function retrieves the thread identifier of the calling thread.

DWORD GetCurrentThreadId(VOID);

Parameters

This function has no parameters.

Return Values

The return value is the thread identifier of the calling thread.

Remarks

Until the thread terminates, the thread identifier uniquely identifies the thread throughout the system.

For example, see Using Thread Local Storage.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetCurrentThread, OpenThread


GetEnvironmentStrings

The GetEnvironmentStrings function retrieves the environment block for the current process.

LPVOID GetEnvironmentStrings(VOID);

Parameters

This function has no parameters.

Return Values

The return value is a pointer to an environment block for the current process.

Remarks

The GetEnvironmentStrings function returns a pointer to the environment block of the calling process. This should be treated as a read-only block; do not modify it directly. Instead, use the GetEnvironmentVariable and SetEnvironmentVariable functions to retrieve or change the environment variables within this block. When the block is no longer needed, it should be freed by calling FreeEnvironmentStrings.

A process can use this function's return value to specify the environment address used by the CreateProcess function.

For example, see Changing Environment Variables.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, GetEnvironmentVariable, SetEnvironmentVariable, FreeEnvironmentStrings


GetEnvironmentVariable

The GetEnvironmentVariable function retrieves the value of the specified variable from the environment block of the calling process. The value is in the form of a null-terminated string of characters.

DWORD GetEnvironmentVariable(
  LPCTSTR lpName,  // environment variable name
  LPTSTR lpBuffer, // buffer for variable value
  DWORD nSize      // size of buffer
);

Parameters

lpName
[in] Pointer to a null-terminated string that specifies the environment variable.
lpBuffer
[out] Pointer to a buffer to receive the value of the specified environment variable.
nSize
[in] Specifies the size, in TCHARs, of the buffer pointed to by the lpBuffer parameter.

Return Values

If the function succeeds, the return value is the number of TCHARs stored into the buffer pointed to by lpBuffer, not including the terminating null character.

If the specified environment variable name was not found in the environment block for the current process, the return value is zero.

If the buffer pointed to by lpBuffer is not large enough, the return value is the buffer size, in TCHARs, required to hold the value string and its terminating null character.

For example, see Changing Environment Variables.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, GetEnvironmentStrings, SetEnvironmentVariable


GetExitCodeProcess

The GetExitCodeProcess function retrieves the termination status of the specified process.

BOOL GetExitCodeProcess(
  HANDLE hProcess,     // handle to the process
  LPDWORD lpExitCode   // termination status
);

Parameters

hProcess
[in] Handle to the process.

Windows NT/2000 or later: The handle must have PROCESS_QUERY_INFORMATION access. For more information, see Process Security and Access Rights.

lpExitCode
[out] Pointer to a variable to receive the process termination status.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the specified process has not terminated, the termination status returned is STILL_ACTIVE. If the process has terminated, the termination status returned may be one of the following:

  • The exit value specified in the ExitProcess or TerminateProcess function.
  • The return value from the main or WinMain function of the process.
  • The exception value for an unhandled exception that caused the process to terminate.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, ExitProcess, ExitThread, TerminateProcess, WinMain


GetExitCodeThread

The GetExitCodeThread function retrieves the termination status of the specified thread.

BOOL GetExitCodeThread(
  HANDLE hThread,      // handle to the thread
  LPDWORD lpExitCode   // termination status
);

Parameters

hThread
[in] Handle to the thread.

Windows NT/2000 or later: The handle must have THREAD_QUERY_INFORMATION access. For more information, see Thread Security and Access Rights.

lpExitCode
[out] Pointer to a variable to receive the thread termination status.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the specified thread has not terminated, the termination status returned is STILL_ACTIVE. If the thread has terminated, the termination status returned may be one of the following:

  • The exit value specified in the ExitThread or TerminateThread function.
  • The return value from the thread function.
  • The exit value of the thread's process.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, ExitThread, GetExitCodeProcess, OpenThread, TerminateThread


GetGuiResources

The GetGuiResources function retrieves the count of handles to graphical user interface (GUI) objects in use by the specified process.

DWORD GetGuiResources (
  HANDLE hProcess,  // handle to process
  DWORD uiFlags     // GUI object type
);

Parameters

hProcess
[in] Handle to the process. The handle must have the PROCESS_QUERY_INFORMATION access right. For more information, see Process Security and Access Rights.
uiFlags
[in] Specifies the GUI object type. This parameter can be one of the following values.
Value | Meaning
GR_GDIOBJECTS | Return the count of GDI objects.
GR_USEROBJECTS | Return the count of USER objects.

Return Values

If the function succeeds, the return value is the count of handles to GUI objects in use by the process. If no GUI objects are in use, the return value is zero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

A process without a graphical user interface does not use GUI resources, therefore, GetGuiResources will return zero.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, GetCurrentProcess, OpenProcess


GetPriorityClass

The GetPriorityClass function retrieves the priority class for the specified process. This value, together with the priority value of each thread of the process, determines each thread's base priority level.

DWORD GetPriorityClass(
  HANDLE hProcess   // handle to process
);

Parameters

hProcess
[in] Handle to the process.

Windows NT/2000 or later: The handle must have PROCESS_QUERY_INFORMATION access. For more information, see Process Security and Access Rights.

Return Values

If the function succeeds, the return value is the priority class of the specified process.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The process's priority class is one of the following values.

Priority | Meaning
ABOVE_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority above NORMAL_PRIORITY_CLASS but below HIGH_PRIORITY_CLASS.
BELOW_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority above IDLE_PRIORITY_CLASS but below NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS | Indicates a process that performs time-critical tasks that must be executed immediately for it to run correctly. The threads of a high-priority class process preempt the threads of normal or idle priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class CPU-bound application can use nearly all available cycles.
IDLE_PRIORITY_CLASS | Indicates a process whose threads run only when the system is idle and are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS | Indicates a normal process with no special scheduling needs.
REALTIME_PRIORITY_CLASS | Indicates a process that has the highest possible priority. The threads of a real-time priority class process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.

Remarks

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The operating system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level will scheduling of threads at a lower level take place.

For a table that shows the base priority levels for each combination of priority class and thread priority value, see the SetPriorityClass function.

Windows NT 4.0 and earlier: Priority class is maintained by the Windows subsystem (csrss), so only Windows-based application have a priority class that can be queried.

Windows 2000 and later: Priority class is maintained by the executive, so all processes have a priority class that can be queried.

For example, see Taking a Snapshot and Viewing Processes.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetThreadPriority, SetPriorityClass, SetThreadPriority


GetProcessAffinityMask

The GetProcessAffinityMask function retrieves the process affinity mask for the specified process and the system affinity mask for the system.

A process affinity mask is a bit vector in which each bit represents the processors that a process is allowed to run on. A system affinity mask is a bit vector in which each bit represents the processors that are configured into a system.

A process affinity mask is a proper subset of a system affinity mask. A process is only allowed to run on the processors configured into a system.

BOOL GetProcessAffinityMask(
  HANDLE hProcess,                  // handle to process
  PDWORD_PTR lpProcessAffinityMask, // process affinity mask
  PDWORD_PTR lpSystemAffinityMask   // system affinity mask
);

Parameters

hProcess
[in] Handle to the process whose affinity mask is desired.

Windows NT/2000 or later: This handle must have PROCESS_QUERY_INFORMATION access. For more information, see Process Security and Access Rights.

lpProcessAffinityMask
[out] Pointer to a variable that receives the affinity mask for the specified process.
lpSystemAffinityMask
[out] Pointer to a variable that receives the affinity mask for the system.

Return Values

If the function succeeds, the return value is nonzero.

Windows NT/2000 or later: Upon success, the function sets the DWORD variables pointed to by lpProcessAffinityMask and lpSystemAffinityMask to the appropriate affinity masks.

Windows 95/98/Me: Upon success, the function sets the DWORD variables pointed to by lpProcessAffinityMask and lpSystemAffinityMask to the value one.

If the function fails, the return value is zero, and the values of the DWORD variables pointed to by lpProcessAffinityMask and lpSystemAffinityMask are undefined. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, SetProcessAffinityMask, SetThreadAffinityMask


GetProcessIoCounters

The GetProcessIoCounters function retrieves accounting information for all I/O operations performed by the specified process.

BOOL GetProcessIoCounters(
  HANDLE hProcess,           // handle to process
  PIO_COUNTERS lpIoCounters  // I/O accouting information
);

Parameters

hProcess
[in] Handle to the process. The handle must have the PROCESS_QUERY access right.
lpIoCounters
[out] Pointer to an IO_COUNTERS structure that receives the I/O accounting information for the process.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, IO_COUNTERS


GetProcessPriorityBoost

The GetProcessPriorityBoost function retrieves the priority boost control state of the specified process.

BOOL GetProcessPriorityBoost(
  HANDLE hProcess,             // handle to process
  PBOOL pDisablePriorityBoost  // priority boost state
);

Parameters

hProcess
[in] Handle to the process. This handle must have the PROCESS_QUERY_INFORMATION access right. For more information, see Process Security and Access Rights.
pDisablePriorityBoost
[out] Pointer to a variable that receives the priority boost control state. A value of TRUE indicates that dynamic boosting is disabled. A value of FALSE indicates normal behavior.

Return Values

If the function succeeds, the return value is nonzero. In that case, the variable pointed to by the pDisablePriorityBoost parameter receives the priority boost control state.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, SetProcessPriorityBoost


GetProcessShutdownParameters

The GetProcessShutdownParameters function retrieves shutdown parameters for the currently calling process.

BOOL GetProcessShutdownParameters(
  LPDWORD lpdwLevel, // shutdown priority
  LPDWORD lpdwFlags  // shutdown flag
);

Parameters

lpdwLevel
[out] Pointer to a variable that receives the shutdown priority level. Higher levels shut down first. System level shutdown orders are reserved for system components. Higher numbers shut down first. Following are the level conventions.
Value | Meaning
000–0FF | System reserved last shutdown range.
100–1FF | Application reserved last shutdown range.
200–2FF | Application reserved "in between" shutdown range.
300–3FF | Application reserved first shutdown range.
400–4FF | System reserved first shutdown range.

All processes start at shutdown level 0x280.

lpdwFlags
[out] Pointer to a variable that receives the shutdown flags. This parameter can be the following value.
Value | Meaning
SHUTDOWN_NORETRY | If this process takes longer than the specified timeout to shut down, do not display a retry dialog box for the user. Instead, just cause the process to directly exit.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, SetProcessShutdownParameters


GetProcessTimes

The GetProcessTimes function retrieves timing information for the specified process.

BOOL GetProcessTimes(
  HANDLE hProcess,           // handle to process
  LPFILETIME lpCreationTime, // process creation time
  LPFILETIME lpExitTime,     // process exit time
  LPFILETIME lpKernelTime,   // process kernel-mode time
  LPFILETIME lpUserTime      // process user-mode time
);

Parameters

hProcess
[in] Handle to the process whose timing information is sought. This handle must be created with PROCESS_QUERY_INFORMATION access. For more information, see Process Security and Access Rights.
lpCreationTime
[out] Pointer to a FILETIME structure that receives the creation time of the process.
lpExitTime
[out] Pointer to a FILETIME structure that receives the exit time of the process. If the process has not exited, the content of this structure is undefined.
lpKernelTime
[out] Pointer to a FILETIME structure that receives the amount of time that the process has executed in kernel mode. The time that each of the threads of the process has executed in kernel mode is determined, and then all of those times are summed together to obtain this value.
lpUserTime
[out] Pointer to a FILETIME structure that receives the amount of time that the process has executed in user mode. The time that each of the threads of the process has executed in user mode is determined, and then all of those times are summed together to obtain this value.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

All times are expressed using FILETIME data structures. Such a structure contains two 32-bit values that combine to form a 64-bit count of 100-nanosecond time units.

Process creation and exit times are points in time expressed as the amount of time that has elapsed since midnight on January 1, 1601 at Greenwich, England. The Win32 API provides several functions that an application can use to convert such values to more generally useful forms.

Process kernel mode and user mode times are amounts of time. For example, if a process has spent one second in kernel mode, this function will fill the FILETIME structure specified by lpKernelTime with a 64-bit value of ten million. That is the number of 100-nanosecond units in one second.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, FILETIME, FileTimeToDosDateTime, FileTimeToLocalFileTime, FileTimeToSystemTime


GetProcessVersion

The GetProcessVersion function retrieves the major and minor version numbers of the system on which the specified process expects to run.

DWORD GetProcessVersion(
  DWORD ProcessId  // process identifier
);

Parameters

ProcessId
[in] Process identifier that specifies the process of interest. A value of zero specifies the calling process.

Return Values

If the function succeeds, the return value is the version of the system on which the process expects to run. The high word of the return value contains the major version number. The low word of the return value contains the minor version number.

If the function fails, the return value is zero. To get extended error information, call GetLastError. The function fails if ProcessId is an invalid value.

Remarks

The GetProcessVersion function performs less quickly when ProcessId is nonzero, specifying a process other than the calling process.

The version number returned by this function is the version number stamped in the image header of the .exe file the process is running. Linker programs set this value.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions


GetProcessWorkingSetSize

The GetProcessWorkingSetSize function retrieves the minimum and maximum working set sizes of the specified process.

The "working set" of a process is the set of memory pages currently visible to the process in physical RAM memory. These pages are resident and available for an application to use without triggering a page fault. The size of a process' working set is specified in bytes. The minimum and maximum working set sizes affect the virtual memory paging behavior of a process.

BOOL GetProcessWorkingSetSize(
  HANDLE hProcess,                 // handle to the process
  PSIZE_T lpMinimumWorkingSetSize, // minimum working set size
  PSIZE_T lpMaximumWorkingSetSize  // maximum working set size
);

Parameters

hProcess
[in] Handle to the process whose working set sizes will be obtained. The handle must have the PROCESS_QUERY_INFORMATION access right. For more information, see Process Security and Access Rights.
lpMinimumWorkingSetSize
[out] Pointer to a variable that receives the minimum working set size of the specified process. The virtual memory manager attempts to keep at least this much memory resident in the process whenever the process is active.
lpMaximumWorkingSetSize
[out] Pointer to a variable that receives the maximum working set size of the specified process. The virtual memory manager attempts to keep no more than this much memory resident in the process whenever the process is active when memory is in short supply.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, SetProcessWorkingSetSize


GetStartupInfo

The GetStartupInfo function retrieves the contents of the STARTUPINFO structure that was specified when the calling process was created.

VOID GetStartupInfo(
  LPSTARTUPINFO lpStartupInfo   // startup information
);

Parameters

lpStartupInfo
[out] Pointer to a STARTUPINFO structure that receives the startup information.

Return Values

This function does not return a value.

Remarks

The STARTUPINFO structure was specified by the process that created the calling process. It can be used to specify properties associated with the main window of the calling process.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, STARTUPINFO


GetThreadPriority

The GetThreadPriority function retrieves the priority value for the specified thread. This value, together with the priority class of the thread's process, determines the thread's base-priority level.

int GetThreadPriority(
  HANDLE hThread   // handle to thread
);

Parameters

hThread
[in] Handle to the thread.

Windows NT/2000 or later: The handle must have THREAD_QUERY_INFORMATION access. For more information, see Thread Security and Access Rights.

Return Values

If the function succeeds, the return value is the thread's priority level.

If the function fails, the return value is THREAD_PRIORITY_ERROR_RETURN. To get extended error information, call GetLastError.

The thread's priority level is one of the following values:

Priority | Meaning
THREAD_PRIORITY_ABOVE_NORMAL | Indicates 1 point above normal priority for the priority class.
THREAD_PRIORITY_BELOW_NORMAL | Indicates 1 point below normal priority for the priority class.
THREAD_PRIORITY_HIGHEST | Indicates 2 points above normal priority for the priority class.
THREAD_PRIORITY_IDLE | Indicates a base-priority level of 1 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 16 for REALTIME_PRIORITY_CLASS processes.
THREAD_PRIORITY_LOWEST | Indicates 2 points below normal priority for the priority class.
THREAD_PRIORITY_NORMAL | Indicates normal priority for the priority class.
THREAD_PRIORITY_TIME_CRITICAL | Indicates a base-priority level of 15 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base-priority level of 31 for REALTIME_PRIORITY_CLASS processes.

Remarks

Every thread has a base-priority level determined by the thread's priority value and the priority class of its process. The operating system uses the base-priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level will scheduling of threads at a lower level take place.

For a table that shows the base-priority levels for each combination of priority class and thread priority value, refer to the SetPriorityClass function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetPriorityClass, OpenThread, SetPriorityClass, SetThreadPriority


GetThreadPriorityBoost

The GetThreadPriorityBoost function retrieves the priority boost control state of the specified thread.

BOOL GetThreadPriorityBoost(
  HANDLE hThread,              // handle to thread
  PBOOL pDisablePriorityBoost  // priority boost state
);

Parameters

hThread
[in] Handle to the thread. This thread must have THREAD_QUERY_INFORMATION access. For more information, see Thread Security and Access Rights.
pDisablePriorityBoost
[out] Pointer to a variable that receives the priority boost control state. A value of TRUE indicates that dynamic boosting is disabled. A value of FALSE indicates normal behavior.

Return Values

If the function succeeds, the return value is nonzero. In that case, the variable pointed to by the pDisablePriorityBoost parameter receives the priority boost control state.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, OpenThread, SetThreadPriorityBoost


GetThreadTimes

The GetThreadTimes function retrieves timing information for the specified thread.

BOOL GetThreadTimes(
  HANDLE hThread,             // handle to thread
  LPFILETIME lpCreationTime,  // thread creation time
  LPFILETIME lpExitTime,      // thread exit time
  LPFILETIME lpKernelTime,    // thread kernel-mode time
  LPFILETIME lpUserTime       // thread user-mode time
);

Parameters

hThread
[in] Handle to the thread whose timing information is sought. This handle must be created with THREAD_QUERY_INFORMATION access. For more information, see Thread Security and Access Rights.
lpCreationTime
[out] Pointer to a FILETIME structure that receives the creation time of the thread.
lpExitTime
[out] Pointer to a FILETIME structure that receives the exit time of the thread. If the thread has not exited, the content of this structure is undefined.
lpKernelTime
[out] Pointer to a FILETIME structure that receives the amount of time that the thread has executed in kernel mode.
lpUserTime
[out] Pointer to a FILETIME structure that receives the amount of time that the thread has executed in user mode.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

All times are expressed using FILETIME data structures. Such a structure contains two 32-bit values that combine to form a 64-bit count of 100-nanosecond time units.

Thread creation and exit times are points in time expressed as the amount of time that has elapsed since midnight on January 1, 1601 at Greenwich, England. The Win32 API provides several functions that an application can use to convert such values to more generally useful forms; see Time Functions, particularly those noted in the following See Also section.

Thread kernel mode and user mode times are amounts of time. For example, if a thread has spent one second in kernel mode, this function will fill the FILETIME structure specified by lpKernelTime with a 64-bit value of ten million. That is the number of 100-nanosecond units in one second.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, FILETIME, FileTimeToDosDateTime, FileTimeToLocalFileTime, FileTimeToSystemTime, OpenThread


IsProcessInJob

[This is preliminary documentation and subject to change.]

The IsProcessInJob function determines if the process is running in the specified job.

BOOL IsProcessInJob (
  HANDLE ProcessHandle,
  HANDLE JobHandle,
  PBOOL Result
);

Parameters

ProcessHandle
[in] Handle to the process to be tested.
JobHandle
[in] Handle to the job. If this parameter is NULL, the function tests if the process is running under any job.
Result
[out] Pointer to a value that receives TRUE if the process is running in the job, and FALSE otherwise.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Whistler.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, AssignProcessToJobObject


OpenJobObject

The OpenJobObject function opens an existing job object.

HANDLE OpenJobObject(
  DWORD dwDesiredAccess,  // access right
  BOOL bInheritHandles,   // inheritance state
  LPCTSTR lpName          // job name
);

Parameters

dwDesiredAccess
[in] Specifies the desired access mode to the job object. This parameter can be one or more of the following values.
Value | Meaning
MAXIMUM_ALLOWED | Specifies maximum access rights to the job object that are valid for the caller.
JOB_OBJECT_ASSIGN_PROCESS | Specifies the assign process access right to the object. Allows processes to be assigned to the job.
JOB_OBJECT_SET_ATTRIBUTES | Specifies the set attribute access right to the object. Allows job object attributes to be set.
JOB_OBJECT_QUERY | Specifies the query access right to the object. Allows job object attributes and accounting information to be queried.
JOB_OBJECT_TERMINATE | Specifies the terminate access right to the object. Allows termination of all processes in the job object.
JOB_OBJECT_SET_SECURITY_ATTRIBUTES | Specifies the security attributes access right to the object. Allows security limitations on all processes in the job object to be set.
JOB_OBJECT_ALL_ACCESS | Specifies the full access right to the job object.

bInheritHandles
[in] Specifies whether the returned handle is inherited when a new process is created. If this parameter is TRUE, the new process inherits the handle.
lpName
[in] Pointer to a null-terminated string specifying the name of the job to be opened. Name comparisons are case sensitive.

Return Values

If the function succeeds, the return value is a handle to the job. The handle provides the requested access to the job.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

To associate a process with a job, use the AssignProcessToJobObject function.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows 2000.

See Also

Processes and Threads Overview, Process and Thread Functions, AssignProcessToJobObject


OpenProcess

The OpenProcess function opens an existing process object.

HANDLE OpenProcess(
  DWORD dwDesiredAccess,  // access flag
  BOOL bInheritHandle,    // handle inheritance option
  DWORD dwProcessId       // process identifier
);

Parameters

dwDesiredAccess
[in] Specifies the access to the process object. For operating systems that support security checking, this access is checked against any security descriptor for the target process. This parameter can be STANDARD_RIGHTS_REQUIRED or one or more of the following values.
Value | Description
PROCESS_ALL_ACCESS | Specifies all possible access flags for the process object.
PROCESS_CREATE_PROCESS | Used internally.
PROCESS_CREATE_THREAD | Enables using the process handle in the CreateRemoteThread function to create a thread in the process.
PROCESS_DUP_HANDLE | Enables using the process handle as either the source or target process in the DuplicateHandle function to duplicate a handle.
PROCESS_QUERY_INFORMATION | Enables using the process handle in the GetExitCodeProcess and GetPriorityClass functions to read information from the process object.
PROCESS_SET_QUOTA | Enables using the process handle in the AssignProcessToJobObject and SetProcessWorkingSetSize functions to set memory limits.
PROCESS_SET_INFORMATION | Enables using the process handle in the SetPriorityClass function to set the priority class of the process.
PROCESS_TERMINATE | Enables using the process handle in the TerminateProcess function to terminate the process.
PROCESS_VM_OPERATION | Enables using the process handle in the VirtualProtectEx and WriteProcessMemory functions to modify the virtual memory of the process.
PROCESS_VM_READ | Enables using the process handle in the ReadProcessMemory function to read from the virtual memory of the process.
PROCESS_VM_WRITE | Enables using the process handle in the WriteProcessMemory function to write to the virtual memory of the process.
SYNCHRONIZE | Windows NT/2000 or later: Enables using the process handle in any of the wait functions to wait for the process to terminate.

bInheritHandle
[in] Specifies whether the returned handle can be inherited by a new process created by the current process. If TRUE, the handle is inheritable.
dwProcessId
[in] Specifies the identifier of the process to open.

Return Values

If the function succeeds, the return value is an open handle to the specified process.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by the OpenProcess function can be used in any function that requires a handle to a process, such as the wait functions, provided the appropriate access rights were requested.

When you are finished with the handle, be sure to close it using the CloseHandle function.

For example, see Taking a Snapshot and Viewing Processes.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, AssignProcessToJobObject, CloseHandle, CreateProcess, CreateRemoteThread, DuplicateHandle, GetCurrentProcess, GetCurrentProcessId, GetExitCodeProcess, GetPriorityClass, ReadProcessMemory, SetPriorityClass, SetProcessWorkingSetSize, TerminateProcess, VirtualProtectEx, WriteProcessMemory


OpenThread

The OpenThread function opens an existing thread object.

HANDLE OpenThread(
  DWORD dwDesiredAccess,  // access right
  BOOL bInheritHandle,    // handle inheritance option
  DWORD dwThreadId        // thread identifier
);

Parameters

dwDesiredAccess
[in] Specifies the desired access to the thread object. For operating systems that support security checking, this access level is checked against any security descriptor for the target thread. This parameter can be STANDARD_RIGHTS_REQUIRED or any combination of the following values.
Value | Description
SYNCHRONIZE | Enables the use of the thread handle in any of the wait functions.
THREAD_ALL_ACCESS | Specifies all possible access flags for the thread object.
THREAD_GET_CONTEXT | Enables the use of the thread handle in the GetThreadContext function.
THREAD_QUERY_INFORMATION | Enables the use of the thread handle to read certain information from the thread object, such as the exit code (see GetExitCodeThread).
THREAD_SET_CONTEXT | Enables the use of the thread handle in the SetThreadContext function.
THREAD_SET_INFORMATION | Enables the use of the thread handle to set certain information for the thread object.
THREAD_SET_THREAD_TOKEN | Enables the use of the thread handle in the SetTokenInformation function to set the thread token.
THREAD_SUSPEND_RESUME | Enables the use of the thread handle in the SuspendThread or ResumeThread function to suspend and resume the thread.
THREAD_TERMINATE | Enables the use of the thread handle in the TerminateThread function to terminate the thread.

bInheritHandle
[in] Indicates whether the returned handle is to be inherited by a new process created by the current process. If this parameter is TRUE, the new process will inherit the handle.
dwThreadId
[in] Specifies the identifier of the thread to open.

Return Values

If the function succeeds, the return value is an open handle to the specified process.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by OpenThread can be used in any function that requires a handle to a thread, such as the wait functions, provided you requested the appropriate access rights. The handle is granted access to the thread object only to the extent it was specified in the dwDesiredAccess parameter.

When you are finished with the handle, be sure to close it by using the CloseHandle function.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Requires Windows Me.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CloseHandle, GetExitCodeThread, GetThreadContext, ResumeThread, SetThreadContext, SetTokenInformation, SuspendThread, TerminateThread


QueryInformationJobObject

The QueryInformationJobObject function retrieves limit and job state information from the job object.

BOOL QueryInformationJobObject(
  HANDLE hJob,                           // handle to job
  JOBOBJECTINFOCLASS JobObjectInfoClass, // information class
  LPVOID lpJobObjectInfo,                // limit information
  DWORD cbJobObjectInfoLength,           // limit information size
  LPDWORD lpReturnLength                 // data written
);

Parameters

hJob
[in] Handle to the job whose information is being queried. The CreateJobObject or OpenJobObject function returns this handle. The handle must have the JOB_OBJECT_QUERY access right associated with it. For more information, see Job Object Security and Access Rights.

If this value is NULL and the calling process is associated with a job, the job associated with the calling process is used.

JobObjectInfoClass
[in] Specifies the information class for limits to be queried. This parameter can be one of the following values.
Value | Meaning
JobObjectBasicAccountingInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_ACCOUNTING_INFORMATION structure.
JobObjectBasicAndIoAccountingInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION structure.
JobObjectBasicLimitInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
JobObjectBasicProcessIdList | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_PROCESS_ID_LIST structure.
JobObjectBasicUIRestrictions | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_UI_RESTRICTIONS structure.
JobObjectExtendedLimitInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure.
JobObjectSecurityLimitInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_SECURITY_LIMIT_INFORMATION structure.

lpJobObjectInfo
[out] Receives the limit information. The format of this data depends on the value of the JobObjectInfoClass parameter.
cbJobObjectInfoLength
[in] Specifies the count, in bytes, of the job information being queried.
lpReturnLength
[out] Pointer to a variable that receives the length of data written to the structure pointed to by the lpJobObjectInfo parameter. If you do not want to receive this information, specify NULL.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

You can use QueryInformationJobObject to obtain the current limits, modify them, then use the SetInformationJobObject function to set new limits.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION, JOBOBJECT_BASIC_LIMIT_INFORMATION, JOBOBJECT_BASIC_PROCESS_ID_LIST, JOBOBJECT_BASIC_UI_RESTRICTIONS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JOBOBJECT_SECURITY_LIMIT_INFORMATION, SetInformationJobObject


QueueUserWorkItem

The QueueUserWorkItem function queues a work item to a worker thread in the thread pool.

BOOL QueueUserWorkItem(
  LPTHREAD_START_ROUTINE Function,  // starting address
  PVOID Context,                    // function data
  ULONG Flags                       // worker options
);

Parameters

Function
[in] Pointer to the application-defined callback function of type LPTHREAD_START_ROUTINE to be executed by the thread in the thread pool. This value represents the starting address of the thread. This callback function must not call the TerminateThread function.

For more information, see ThreadProc.

Context
[in] Specifies a single parameter value that will be passed to the thread function.
Flags
[in] This parameter can be one or more of the following values.
Value | Meaning
WT_EXECUTEDEFAULT | By default, the callback function is queued to a non-I/O worker thread.
WT_EXECUTEINIOTHREAD The callback function is queued to an I/O worker thread. This flag should be used if the function should be executed in a thread that waits in an alertable state.

The callback function is queued as an APC. Be sure to address reentrancy issues if the function performs an alertable wait operation.

WT_EXECUTEINPERSISTENTTHREAD The callback function is queued to a thread that never terminates. This flag should be used only for short tasks or it could affect other timer operations.

Note that currently no worker thread is truly persistent, although worker threads do not terminate if there are any pending I/O requests.
WT_EXECUTELONGFUNCTION | Specifies that the callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If a function in a DLL is queued to a worker thread, be sure that the function has completed execution before the DLL is unloaded.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, ThreadProc, Thread Pooling


ResumeThread

The ResumeThread function decrements a thread's suspend count. When the suspend count is decremented to zero, the execution of the thread is resumed.

DWORD ResumeThread(
  HANDLE hThread   // handle to thread
);

Parameters

hThread
[in] Handle to the thread to be restarted.

Windows NT/2000 or later: The handle must have THREAD_SUSPEND_RESUME access to the thread. For more information, see Thread Security and Access Rights.

Return Values

If the function succeeds, the return value is the thread's previous suspend count.

If the function fails, the return value is -1. To get extended error information, call GetLastError.

Remarks

The ResumeThread function checks the suspend count of the subject thread. If the suspend count is zero, the thread is not currently suspended. Otherwise, the subject thread's suspend count is decremented. If the resulting value is zero, then the execution of the subject thread is resumed.

If the return value is zero, the specified thread was not suspended. If the return value is 1, the specified thread was suspended but was restarted. If the return value is greater than 1, the specified thread is still suspended.

Note that while reporting debug events, all threads within the reporting process are frozen. Debuggers are expected to use the SuspendThread and ResumeThread functions to limit the set of threads that can execute within a process. By suspending all threads in a process except for the one reporting a debug event, it is possible to "single step" a single thread. The other threads are not released by a continue operation if they are suspended.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, OpenThread, SuspendThread


SetEnvironmentVariable

The SetEnvironmentVariable function sets the value of an environment variable for the current process.

BOOL SetEnvironmentVariable(
  LPCTSTR lpName,  // environment variable name
  LPCTSTR lpValue  // new value for variable
);

Parameters

lpName
[in] Pointer to a null-terminated string that specifies the environment variable whose value is being set. The operating system creates the environment variable if it does not exist and lpValue is not NULL.
lpValue
[in] Pointer to a null-terminated string containing the new value of the specified environment variable. If this parameter is NULL, the variable is deleted from the current process's environment.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

This function has no effect on the system environment variables or the environment variables of other processes.

To add or modify system environment variables, the user selects System from the Control Panel, then selects the Environment tab. The user can also add or modify environment variables at a command prompt using the set command. Environment variables created with the set command apply only to the command window in which they are set, and to its child processes. For more information, type set /? at a command prompt.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Processes and Threads Overview, Process and Thread Functions, GetEnvironmentVariable


SetInformationJobObject

The SetInformationJobObject function sets limits for a job object.

BOOL SetInformationJobObject(
  HANDLE hJob,                           // handle to job
  JOBOBJECTINFOCLASS JobObjectInfoClass, // information class
  LPVOID lpJobObjectInfo,                // limit information
  DWORD cbJobObjectInfoLength            // size of limit information
);

Parameters

hJob
[in] Handle to the job whose limits are being set. The CreateJobObject or OpenJobObject function returns this handle. The handle must have the JOB_OBJECT_SET_ATTRIBUTES access right associated with it. For more information, see Job Object Security and Access Rights.
JobObjectInfoClass
[in] Specifies the information class for limits to be set. This parameter can be one of the following values.
Value | Meaning
JobObjectAssociateCompletionPortInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_ASSOCIATE_COMPLETION_PORT structure.
JobObjectBasicLimitInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.
JobObjectBasicUIRestrictions | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_BASIC_UI_RESTRICTIONS structure.
JobObjectEndOfJobTimeInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure.
JobObjectExtendedLimitInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure.
JobObjectSecurityLimitInformation | The lpJobObjectInfo parameter is a pointer to a JOBOBJECT_SECURITY_LIMIT_INFORMATION structure. The hJob handle must have the JOB_OBJECT_SET_SECURITY_ATTRIBUTES access right associated with it.

lpJobObjectInfo
[in] Specifies the limits to be set for the job. The format of this data depends on the value of JobObjectInfoClass.
cbJobObjectInfoLength
[in] Specifies the count, in bytes, of the job information being set.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

You can use the SetInformationJobObject function to set several limits in a single call. If you want to establish the limits one at a time or change a subset of the limits, call the QueryInformationJobObject function to obtain the current limits, modify these limits, and then call SetInformationJobObject.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, JOBOBJECT_ASSOCIATE_COMPLETION_PORT, JOBOBJECT_BASIC_LIMIT_INFORMATION, JOBOBJECT_BASIC_UI_RESTRICTIONS, JOBOBJECT_END_OF_JOB_TIME_INFORMATION, JOBOBJECT_EXTENDED_LIMIT_INFORMATION, JOBOBJECT_SECURITY_LIMIT_INFORMATION , QueryInformationJobObject


SetPriorityClass

The SetPriorityClass function sets the priority class for the specified process. This value together with the priority value of each thread of the process determines each thread's base priority level.

BOOL SetPriorityClass(
  HANDLE hProcess,        // handle to process
  DWORD dwPriorityClass   // priority class
);

Parameters

hProcess
[in] Handle to the process.

Windows NT/2000 or later: The handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process Security and Access Rights.

dwPriorityClass
[in] Specifies the priority class for the process. This parameter can be one of the following values.
Priority | Meaning
ABOVE_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority above NORMAL_PRIORITY_CLASS but below HIGH_PRIORITY_CLASS.
BELOW_NORMAL_PRIORITY_CLASS | Windows 2000 and later: Indicates a process that has priority above IDLE_PRIORITY_CLASS but below NORMAL_PRIORITY_CLASS.
HIGH_PRIORITY_CLASS | Specify this class for a process that performs time-critical tasks that must be executed immediately. The threads of the process preempt the threads of normal or idle priority class processes. An example is the Task List, which must respond quickly when called by the user, regardless of the load on the operating system. Use extreme care when using the high-priority class, because a high-priority class application can use nearly all available CPU time.
IDLE_PRIORITY_CLASS | Specify this class for a process whose threads run only when the system is idle. The threads of the process are preempted by the threads of any process running in a higher priority class. An example is a screen saver. The idle-priority class is inherited by child processes.
NORMAL_PRIORITY_CLASS | Specify this class for a process with no special scheduling needs.
REALTIME_PRIORITY_CLASS | Specify this class for a process that has the highest possible priority. The threads of the process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. The SetThreadPriority function enables setting the base priority level of a thread relative to the priority class of its process. For more information, see Scheduling Priorities.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, CreateThread, GetPriorityClass, GetThreadPriority, SetThreadPriority


SetProcessAffinityMask

The SetProcessAffinityMask function sets a processor affinity mask for the threads of the specified process.

A process affinity mask is a bit vector in which each bit represents the processor on which the threads of the process are allowed to run.

The value of the process affinity mask must be a proper subset of the mask values obtained by the GetProcessAffinityMask function.

BOOL SetProcessAffinityMask(
  HANDLE hProcess,                 // handle to process
  DWORD_PTR dwProcessAffinityMask  // process affinity mask
);

Parameters

hProcess
[in] Handle to the process whose affinity mask is to be set. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process Security and Access Rights.
dwProcessAffinityMask
[in] Specifies an affinity mask for the threads of the process.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Process affinity is inherited by any process that you start with the CreateProcess function.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, GetProcessAffinityMask


SetProcessPriorityBoost

The SetProcessPriorityBoost function disables the ability of the system to temporarily boost the priority of the threads of the specified process.

BOOL SetProcessPriorityBoost(
  HANDLE hProcess,           // handle to process
  BOOL DisablePriorityBoost  // priority boost state
);

Parameters

hProcess
[in] Handle to the process. This handle must have the PROCESS_SET_INFORMATION access right. For more information, see Process Security and Access Rights.
DisablePriorityBoost
[in] Specifies the priority boost control state. A value of TRUE indicates that dynamic boosting is to be disabled. A value of FALSE restores normal behavior.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

When a thread is running in one of the dynamic priority classes, the system temporarily boosts the thread's priority when it is taken out of a wait state. If SetProcessPriorityBoost is called with the DisablePriorityBoost parameter set to TRUE, its threads' priorities are not boosted. This setting affects all existing threads and any threads subsequently created by the process. To restore normal behavior, call SetProcessPriorityBoost with DisablePriorityBoost set to FALSE.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetProcessPriorityBoost


SetProcessShutdownParameters

The SetProcessShutdownParameters function sets shutdown parameters for the currently calling process. This function sets a shutdown order for a process relative to the other processes in the system.

BOOL SetProcessShutdownParameters(
  DWORD dwLevel,  // shutdown priority
  DWORD dwFlags   // shutdown options
);

Parameters

dwLevel
[in] Specifies the shutdown priority for a process relative to other processes in the system. The system shuts down processes from high dwLevel values to low. The highest and lowest shutdown priorities are reserved for system components. This parameter must be in the following range of values.
Value | Meaning
000–0FF | System reserved last shutdown range.
100–1FF | Application reserved last shutdown range.
200–2FF | Application reserved "in between" shutdown range.
300–3FF | Application reserved first shutdown range.
400–4FF | System reserved first shutdown range.

All processes start at shutdown level 0x280.

dwFlags
[in] This parameter can be the following value.
Value | Meaning
SHUTDOWN_NORETRY | Specifies whether to retry the shutdown if the specified time-out period expires. If this flag is specified, the system terminates the process without displaying a retry dialog box for the user.

Return Values

If the function is succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Applications running in the system security context do not get shut down by the operating system. They get notified of shutdown or logoff through the callback function installable via SetConsoleCtrlHandler. They also get notified in the order specified by the dwLevel parameter.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetProcessShutdownParameters, SetConsoleCtrlHandler


SetProcessWorkingSetSize

The SetProcessWorkingSetSize function sets the minimum and maximum working set sizes for the specified process.

The working set of a process is the set of memory pages currently visible to the process in physical RAM memory. These pages are resident and available for an application to use without triggering a page fault. The size of the working set of a process is specified in bytes. The minimum and maximum working set sizes affect the virtual memory paging behavior of a process.

BOOL SetProcessWorkingSetSize(
  HANDLE hProcess,                 // handle to process
  SIZE_T dwMinimumWorkingSetSize,  // minimum working set size
  SIZE_T dwMaximumWorkingSetSize   // maximum working set size
);

Parameters

hProcess
[in] Handle to the process whose working set sizes is to be set.

Windows NT/2000 or later: The handle must have PROCESS_SET_QUOTA access rights. For more information, see Process Security and Access Rights.

dwMinimumWorkingSetSize
[in] Specifies a minimum working set size for the process. The virtual memory manager attempts to keep at least this much memory resident in the process whenever the process is active.

If both dwMinimumWorkingSetSize and dwMaximumWorkingSetSize have the value -1, the function temporarily trims the working set of the specified process to zero. This essentially swaps the process out of physical RAM memory.

dwMaximumWorkingSetSize
[in] Specifies a maximum working set size for the process. The virtual memory manager attempts to keep no more than this much memory resident in the process whenever the process is active and memory is in short supply.

If both dwMinimumWorkingSetSize and dwMaximumWorkingSetSize have the value -1, the function temporarily trims the working set of the specified process to zero. This essentially swaps the process out of physical RAM memory.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. Call GetLastError to obtain extended error information.

Remarks

The working set of the specified process can be emptied by specifying the value -1 for both the minimum and maximum working set sizes.

If the values of either dwMinimumWorkingSetSize or dwMaximumWorkingSetSize are greater than the process' current working set sizes, the specified process must have the SE_INC_BASE_PRIORITY_NAME privilege. Users in the Administrators and Power Users groups generally have this privilege. For more information about security privileges, see Privileges.

The operating system allocates working set sizes on a first-come, first-served basis. For example, if an application successfully sets 40 megabytes as its minimum working set size on a 64-megabyte system, and a second application requests a 40-megabyte working set size, the operating system denies the second application's request.

Using the SetProcessWorkingSetSize function to set an application's minimum and maximum working set sizes does not guarantee that the requested memory will be reserved, or that it will remain resident at all times. When the application is idle, or a low-memory situation causes a demand for memory, the operating system can reduce the application's working set. An application can use the VirtualLock function to lock ranges of the application's virtual address space in memory; however, that can potentially degrade the performance of the system.

When you increase the working set size of an application, you are taking away physical memory from the rest of the system. This can degrade the performance of other applications and the system as a whole. It can also lead to failures of operations that require physical memory to be present; for example, creating processes, threads, and kernel pool. Thus, you must use the SetProcessWorkingSetSize function carefully. You must always consider the performance of the whole system when you are designing an application.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetProcessWorkingSetSize, VirtualLock


SetThreadAffinityMask

The SetThreadAffinityMask function sets a processor affinity mask for the specified thread.

A thread affinity mask is a bit vector in which each bit represents the processors that a thread is allowed to run on.

A thread affinity mask must be a proper subset of the process affinity mask for the containing process of a thread. A thread is only allowed to run on the processors its process is allowed to run on.

DWORD_PTR SetThreadAffinityMask (
  HANDLE hThread,                 // handle to thread
  DWORD_PTR dwThreadAffinityMask  // thread affinity mask
);

Parameters

hThread
[in] Handle to the thread whose affinity mask is to be set.

Windows NT/2000 or later: This handle must have the THREAD_SET_INFORMATION access right associated with it. For more information, see Thread Security and Access Rights.

dwThreadAffinityMask
Windows NT/2000 or later: [in] Specifies an affinity mask for the thread.

Windows 95/98/Me: [in] This value must be 1.

Return Values

If the function succeeds, the return value is nonzero.

Windows NT/2000 or later: The return value is the thread's previous affinity mask.

Windows 95/98/Me: The return value is 1. To succeed, hThread must be valid and dwThreadAffinityMask must be 1.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetProcessAffinityMask, OpenThread, SetThreadIdealProcessor


SetThreadIdealProcessor

The SetThreadIdealProcessor function sets a preferred processor for a thread. The system schedules threads on their preferred processors whenever possible.

DWORD SetThreadIdealProcessor(
  HANDLE hThread,         // handle to the thread
  DWORD dwIdealProcessor  // ideal processor number
);

Parameters

hThread
[in] Handle to the thread whose preferred processor is to be set. The handle must have the THREAD_SET_INFORMATION access right associated with it. For more information, see Thread Security and Access Rights.
dwIdealProcessor
[in] Specifies the number of the preferred processor for the thread. A value of MAXIMUM_PROCESSORS tells the system that the thread has no preferred processor.

Return Values

If the function succeeds, the return value is the previous preferred processor or MAXIMUM_PROCESSORS if the thread does not have a preferred processor.

If the function fails, the return value is – 1. To get extended error information, call GetLastError.

Remarks

You can use the GetSystemInfo function to determine the number of processors on the computer. You can also use the GetProcessAffinityMask function to check the processors on which the thread is allowed to run. Note that GetProcessAffinityMask returns a bit mask whereas SetThreadIdealProcessor uses an integer value to represent the processor.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetProcessAffinityMask, GetSystemInfo, OpenThread, SetThreadAffinityMask


SetThreadPriority

The SetThreadPriority function sets the priority value for the specified thread. This value, together with the priority class of the thread's process, determines the thread's base priority level.

BOOL SetThreadPriority(
  HANDLE hThread, // handle to the thread
  int nPriority   // thread priority level
);

Parameters

hThread
[in] Handle to the thread whose priority value is to be set.

Windows NT/2000 or later: The handle must have the THREAD_SET_INFORMATION access right associated with it. For more information, see Thread Security and Access Rights.

nPriority
[in] Specifies the priority value for the thread. This parameter can be one of the following values:
Priority | Meaning
THREAD_PRIORITY_ABOVE_NORMAL | Indicates 1 point above normal priority for the priority class.
THREAD_PRIORITY_BELOW_NORMAL | Indicates 1 point below normal priority for the priority class.
THREAD_PRIORITY_HIGHEST | Indicates 2 points above normal priority for the priority class.
THREAD_PRIORITY_IDLE | Indicates a base priority level of 1 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base priority level of 16 for REALTIME_PRIORITY_CLASS processes.
THREAD_PRIORITY_LOWEST | Indicates 2 points below normal priority for the priority class.
THREAD_PRIORITY_NORMAL | Indicates normal priority for the priority class.
THREAD_PRIORITY_TIME_CRITICAL | Indicates a base priority level of 15 for IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, or HIGH_PRIORITY_CLASS processes, and a base priority level of 31 for REALTIME_PRIORITY_CLASS processes.

Windows 2000 and later: This parameter can also be -7, -6, -5, -4, -3, 3, 4, 5, or 6. For more information, see Scheduling Priorities.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Every thread has a base priority level determined by the thread's priority value and the priority class of its process. The system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level does scheduling of threads at a lower level take place.

The SetThreadPriority function enables setting the base priority level of a thread relative to the priority class of its process. For example, specifying THREAD_PRIORITY_HIGHEST in a call to SetThreadPriority for a thread of an IDLE_PRIORITY_CLASS process sets the thread's base priority level to 6. For a table that shows the base priority levels for each combination of priority class and thread priority value, see Scheduling Priorities.

For IDLE_PRIORITY_CLASS, BELOW_NORMAL_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, ABOVE_NORMAL_PRIORITY_CLASS, and HIGH_PRIORITY_CLASS processes, the system dynamically boosts a thread's base priority level when events occur that are important to the thread. REALTIME_PRIORITY_CLASS processes do not receive dynamic boosts.

All threads initially start at THREAD_PRIORITY_NORMAL. Use the GetPriorityClass and SetPriorityClass functions to get and set the priority class of a process. Use the GetThreadPriority function to get the priority value of a thread.

Use the priority class of a process to differentiate between applications that are time critical and those that have normal or below normal scheduling requirements. Use thread priority values to differentiate the relative priorities of the tasks of a process. For example, a thread that handles input for a window could have a higher priority level than a thread that performs intensive calculations for the CPU.

When manipulating priorities, be very careful to ensure that a high-priority thread does not consume all of the available CPU time. A thread with a base priority level above 11 interferes with the normal operation of the operating system. Using REALTIME_PRIORITY_CLASS may cause disk caches to not flush, hang the mouse, and so on.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetPriorityClass, GetThreadPriority, SetPriorityClass


SetThreadPriorityBoost

The SetThreadPriorityBoost function disables the ability of the system to temporarily boost the priority of a thread.

BOOL SetThreadPriorityBoost(
  HANDLE hThread,            // handle to thread
  BOOL DisablePriorityBoost  // priority boost state
);

Parameters

hThread
[in] Handle to the thread whose priority is to be boosted. This thread must have the THREAD_SET_INFORMATION access right associated with it. For more information, see Thread Security and Access Rights.
DisablePriorityBoost
[in] Specifies the priority boost control state. A value of TRUE indicates that dynamic boosting is to be disabled. A value of FALSE restores normal behavior.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

When a thread is running in one of the dynamic priority classes, the system temporarily boosts the thread's priority when it is taken out of a wait state. If SetThreadPriorityBoost is called with the DisablePriorityBoost parameter set to TRUE, the thread's priority is not boosted. To restore normal behavior, call SetThreadPriorityBoost with DisablePriorityBoost set to FALSE.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, OpenThread, GetThreadPriorityBoost


Sleep

The Sleep function suspends the execution of the current thread for the specified interval.

To enter an alertable wait state, use the SleepEx function.

VOID Sleep(
  DWORD dwMilliseconds   // sleep time
);

Parameters

dwMilliseconds
[in] Specifies the time, in milliseconds, for which to suspend execution. A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution. A value of INFINITE causes an infinite delay.

Return Values

This function does not return a value.

Remarks

A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.

You have to be careful when using Sleep and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. If you have a thread that uses Sleep with infinite delay, the system will deadlock. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than Sleep.

MAPI: For more information, see Syntax and Limitations for Win32 Functions Useful in MAPI Development.

For example, see Using Thread Local Storage.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx, SleepEx


SleepEx

The SleepEx function suspends the current thread until one of the following occurs:

  • An I/O completion callback function is called
  • An asynchronous procedure call (APC) is queued to the thread.
  • The time-out interval elapses
DWORD SleepEx(
  DWORD dwMilliseconds,  // time-out interval
  BOOL bAlertable        // early completion option
);

Parameters

dwMilliseconds
[in] Specifies the time, in milliseconds, that the delay is to occur. A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution. A value of INFINITE causes an infinite delay.
bAlertable
[in] Specifies whether the function may terminate early due to an I/O completion callback function or an APC. If bAlertable is FALSE, the function does not return until the time-out period has elapsed. If an I/O completion callback occurs, the function does not return and the I/O completion function is not executed. If an APC is queued to the thread, the function does not return and the APC function is not executed.

If bAlertable is TRUE and the thread that called this function is the same thread that called the extended I/O function (ReadFileEx or WriteFileEx), the function returns when either the time-out period has elapsed or when an I/O completion callback function occurs. If an I/O completion callback occurs, the I/O completion function is called. If an APC is queued to the thread (QueueUserAPC), the function returns when either the timer-out period has elapsed or when the APC function is called.

Return Values

The return value is zero if the specified time interval expired.

The return value is WAIT_IO_COMPLETION if the function returned due to one or more I/O completion callback functions. This can happen only if bAlertable is TRUE, and if the thread that called the SleepEx function is the same thread that called the extended I/O function.

Remarks

This function can be used with the ReadFileEx or WriteFileEx functions to suspend a thread until an I/O operation has been completed. These functions specify a completion routine that is to be executed when the I/O operation has been completed. For the completion routine to be executed, the thread that called the I/O function must be in an alertable wait state when the completion callback function occurs. A thread goes into an alertable wait state by calling either SleepEx, MsgWaitForMultipleObjectsEx, WaitForSingleObjectEx, or WaitForMultipleObjectsEx, with the function's bAlertable parameter set to TRUE.

A thread can relinquish the remainder of its time slice by calling this function with a sleep time of zero milliseconds.

You have to be careful when using SleepEx and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. If you have a thread that uses SleepEx with infinite delay, the system will deadlock. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than SleepEx.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx, QueueUserAPC, ReadFileEx, Sleep, WaitForMultipleObjectsEx, WaitForSingleObjectEx, WriteFileEx


SuspendThread

The SuspendThread function suspends the specified thread.

DWORD SuspendThread(
  HANDLE hThread   // handle to thread
);

Parameters

hThread
[in] Handle to the thread that is to be suspended.

Windows NT/2000 or later: The handle must have THREAD_SUSPEND_RESUME access. For more information, see Thread Security and Access Rights.

Return Values

If the function succeeds, the return value is the thread's previous suspend count; otherwise, it is -1. To get extended error information, use the GetLastError function.

Remarks

If the function succeeds, execution of the specified thread is suspended and the thread's suspend count is incremented.

Suspending a thread causes the thread to stop executing user-mode (application) code.

Each thread has a suspend count (with a maximum value of MAXIMUM_SUSPEND_COUNT). If the suspend count is greater than zero, the thread is suspended; otherwise, the thread is not suspended and is eligible for execution. Calling SuspendThread causes the target thread's suspend count to be incremented. Attempting to increment past the maximum suspend count causes an error without incrementing the count.

The ResumeThread function decrements the suspend count of a suspended thread.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, OpenThread, ResumeThread


SwitchToFiber

The SwitchToFiber function schedules a fiber. The caller of must be a fiber.

VOID SwitchToFiber(
  LPVOID lpFiber  // fiber to schedule
);

Parameters

lpFiber
[in] Specifies the address of the fiber to schedule.

Return Values

This function does not return a value.

Remarks

You create fibers with CreateFiber. Before you can schedule fibers associated with a thread, you must call ConvertThreadToFiber to set up an area in which to save the fiber state information. The thread is now the currently executing fiber.

The SwitchToFiber function saves the state information of the current fiber and restores the state of the specified fiber. You can call SwitchToFiber with the address of a fiber created by a different thread. To do this, you must have the address returned to the other thread when it called CreateFiber and you must use proper synchronization.

Warning Avoid making the following call:

SwitchToFiber( GetCurrentFiber() );

This call may cause unpredictable problems.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateFiber, ConvertThreadToFiber


SwitchToThread

The SwitchToThread function causes the calling thread to yield execution to another thread that is ready to run on the current processor. The operating system selects the thread to yield to.

BOOL SwitchToThread(VOID);

Parameters

This function has no parameters.

Return Values

If calling the SwitchToThread function causes the operating system to switch execution to another thread, the return value is nonzero.

If there are no other threads ready to execute, the operating system does not switch execution to another thread, and the return value is zero.

Remarks

The yield of execution is in effect for up to one thread-scheduling time slice. After that, the operating system reschedules execution for the yielding thread. The rescheduling is determined by the priority of the yielding thread and the status of other threads that are available to run.

Note The yield of execution is limited to the processor of the calling thread. The operating system will not switch execution to another processor, even if that processor is idle or is running a thread of lower priority.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, SuspendThread


TerminateJobObject

The TerminateJobObject function terminates all processes currently associated with the job.

BOOL TerminateJobObject(
  HANDLE hJob,    // handle to job
  UINT uExitCode  // exit code
);

Parameters

hJob
[in] Handle to the job whose processes will be terminated. The CreateJobObject or OpenJobObject function returns this handle. This handle must have the JOB_OBJECT_TERMINATE access right. For more information, see Job Object Security and Access Rights.
uExitCode
[in] Specifies the exit code for the processes and threads terminated as a result of this call.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

It is not possible for any of the processes associated with the job to postpone or handle the termination. It is as if TerminateProcess were called for each process associated with the job.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateJobObject, OpenJobObject, TerminateProcess


TerminateProcess

The TerminateProcess function terminates the specified process and all of its threads.

BOOL TerminateProcess(
  HANDLE hProcess, // handle to the process
  UINT uExitCode   // exit code for the process
);

Parameters

hProcess
[in] Handle to the process to terminate.

Windows NT/2000 or later: The handle must have PROCESS_TERMINATE access. For more information, see Process Security and Access Rights.

uExitCode
[in] Specifies the exit code for the process and for all threads terminated as a result of this call. Use the GetExitCodeProcess function to retrieve the process's exit value. Use the GetExitCodeThread function to retrieve a thread's exit value.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The TerminateProcess function is used to unconditionally cause a process to exit. Use it only in extreme circumstances. The state of global data maintained by dynamic-link libraries (DLLs) may be compromised if TerminateProcess is used rather than ExitProcess.

TerminateProcess causes all threads within a process to terminate, and causes a process to exit, but DLLs attached to the process are not notified that the process is terminating.

Terminating a process causes the following:

  1. All of the object handles opened by the process are closed.
  2. All of the threads in the process terminate their execution.
  3. The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.
  4. The states of all threads of the process become signaled, satisfying any threads that had been waiting for the threads to terminate.
  5. The termination status of the process changes from STILL_ACTIVE to the exit value of the process.

Terminating a process does not cause child processes to be terminated.

Terminating a process does not necessarily remove the process object from the system. A process object is deleted when the last handle to the process is closed.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, ExitProcess, OpenProcess, GetExitCodeProcess, GetExitCodeThread


TerminateThread

The TerminateThread function terminates a thread.

BOOL TerminateThread(
  HANDLE hThread,    // handle to thread
  DWORD dwExitCode   // exit code
);

Parameters

hThread
[in/out] Handle to the thread to terminate.

Windows NT/2000 or later: The handle must have THREAD_TERMINATE access. For more information, see Thread Security and Access Rights.

dwExitCode
[in] Specifies the exit code for the thread. Use the GetExitCodeThread function to retrieve a thread's exit value.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

TerminateThread is used to cause a thread to exit. When this occurs, the target thread has no chance to execute any user-mode code and its initial stack is not deallocated. DLLs attached to the thread are not notified that the thread is terminating.

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

  • If the target thread owns a critical section, the critical section will not be released.
  • If the target thread is allocating memory from the heap, the heap lock will not be released.
  • If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
  • If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.

A thread cannot protect itself against TerminateThread, other than by controlling access to its handles. The thread handle returned by the CreateThread and CreateProcess functions has THREAD_TERMINATE access, so any caller holding one of these handles can terminate your thread.

If the target thread is the last thread of a process when this function is called, the thread's process is also terminated.

The state of the thread object becomes signaled, releasing any other threads that had been waiting for the thread to terminate. The thread's termination status changes from STILL_ACTIVE to the value of the dwExitCode parameter.

Terminating a thread does not necessarily remove the thread object from the system. A thread object is deleted when the last thread handle is closed.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, CreateThread, ExitThread, GetExitCodeThread, OpenThread


ThreadProc

The ThreadProc function is an application-defined function that serves as the starting address for a thread. Specify this address when calling the CreateThread or CreateRemoteThread function. The LPTHREAD_START_ROUTINE type defines a pointer to this callback function. ThreadProc is a placeholder for the application-defined function name.

DWORD WINAPI ThreadProc(
  LPVOID lpParameter   // thread data
);

Parameters

lpParameter
[in] Receives the thread data passed to the function using the lpParameter parameter of the CreateThread or CreateRemoteThread function.

Return Values

The function should return a value that indicates its success or failure.

Remarks

A process can obtain the return value of the ThreadProc of a thread it created with CreateThread by calling the GetExitCodeThread function. A process cannot obtain the return value from the ThreadProc of a thread it created with CreateRemoteThread.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateThread, CreateRemoteThread, GetExitCodeThread


TlsAlloc

The TlsAlloc function allocates a thread local storage (TLS) index. Any thread of the process can subsequently use this index to store and retrieve values that are local to the thread.

DWORD TlsAlloc(VOID);

Parameters

This function has no parameters.

Return Values

If the function succeeds, the return value is a TLS index initialized to zero.

If the function fails, the return value is TLS_OUT_OF_INDEXES. To get extended error information, call GetLastError.

Remarks

The threads of the process can use the TLS index in subsequent calls to the TlsFree, TlsSetValue, or TlsGetValue functions.

TLS indexes are typically allocated during process or dynamic-link library (DLL) initialization. Once allocated, each thread of the process can use a TLS index to access its own TLS storage slot. To store a value in its slot, a thread specifies the index in a call to TlsSetValue. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.

The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. This minimum is guaranteed to be at least 64 for all systems.

Windows 2000 and later: There is a limit of 1088 TLS indexes per process.
Windows NT 4.0 and earlier: There is a limit of 64 TLS indexes per process.

TLS indexes are not valid across process boundaries. A DLL cannot assume that an index assigned in one process is valid in another process.

A DLL might use TlsAlloc, TlsSetValue, TlsGetValue, and TlsFree as follows:

  1. When a DLL attaches to a process, the DLL uses TlsAlloc to allocate a TLS index. The DLL then allocates some dynamic storage and uses the TLS index in a call to TlsSetValue to store the address in the TLS slot. This concludes the per-thread initialization for the initial thread of the process. The TLS index is stored in a global or static variable of the DLL.
  2. Each time the DLL attaches to a new thread of the process, the DLL allocates some dynamic storage for the new thread and uses the TLS index in a call to TlsSetValue to store the address in the TLS slot. This concludes the per-thread initialization for the new thread.
  3. Each time an initialized thread makes a DLL call requiring the data in its dynamic storage, the DLL uses the TLS index in a call to TlsGetValue to retrieve the address of the dynamic storage for that thread.

For additional information on thread local storage, see Thread Local Storage.

For example, see Using Thread Local Storage.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, TlsFree, TlsGetValue, TlsSetValue


TlsFree

The TlsFree function releases a thread local storage (TLS) index, making it available for reuse.

BOOL TlsFree(
  DWORD dwTlsIndex   // TLS index
);

Parameters

dwTlsIndex
[in] Specifies a TLS index that was allocated by the TlsAlloc function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the threads of the process have allocated dynamic storage and used the TLS index to store pointers to this storage, they should free the storage before calling TlsFree. The TlsFree function does not free any dynamic storage that has been associated with the TLS index. It is expected that DLLs call this function (if at all) only during their process detach routine.

For a brief discussion of typical uses of the TLS functions, see the Remarks section of the TlsAlloc function.

For example, see Using Thread Local Storage in a Dynamic-Link Library.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, TlsAlloc, TlsGetValue, TlsSetValue


TlsGetValue

The TlsGetValue function retrieves the value in the calling thread's thread local storage (TLS) slot for the specified TLS index. Each thread of a process has its own slot for each TLS index.

LPVOID TlsGetValue(
  DWORD dwTlsIndex   // TLS index
);

Parameters

dwTlsIndex
[in] Specifies a TLS index that was allocated by the TlsAlloc function.

Return Values

If the function succeeds, the return value is the value stored in the calling thread's TLS slot associated with the specified index.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Note The data stored in a TLS slot can have a value of zero. In this case, the return value is zero and GetLastError returns NO_ERROR.

Remarks

TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. After it is allocated, each thread of the process can use a TLS index to access its own TLS storage slot for that index. The storage slot for each thread is initialized to NULL. A thread specifies a TLS index in a call to TlsSetValue, to store a value in its slot. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.

TlsSetValue and TlsGetValue were implemented with speed as the primary goal. These functions perform minimal parameter validation and error checking. In particular, this function succeeds if dwTlsIndex is in the range 0 through (TLS_MINIMUM_AVAILABLE – 1). It is up to the programmer to ensure that the index is valid.

Functions that return indications of failure call SetLastError when they fail. They generally do not call SetLastError when they succeed. The TlsGetValue function is an exception to this general rule. The TlsGetValue function calls SetLastError to clear a thread's last error when it succeeds. That allows checking for the error-free retrieval of NULL values.

For example, see Using Thread Local Storage.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, GetLastError, SetLastError, TlsAlloc, TlsFree, TlsSetValue


TlsSetValue

The TlsSetValue function stores a value in the calling thread's thread local storage (TLS) slot for the specified TLS index. Each thread of a process has its own slot for each TLS index.

BOOL TlsSetValue(
  DWORD dwTlsIndex,  // TLS index
  LPVOID lpTlsValue  // value to store
);

Parameters

dwTlsIndex
[in] Specifies a TLS index that was allocated by the TlsAlloc function.
lpTlsValue
[in] Specifies the value to be stored in the calling thread's TLS slot specified by dwTlsIndex.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

TLS indexes are typically allocated by the TlsAlloc function during process or DLL initialization. Once allocated, each thread of the process can use a TLS index to access its own TLS storage slot for that index. The storage slot for each thread is initialized to NULL. A thread specifies a TLS index in a call to TlsSetValue, to store a value in its slot. The thread specifies the same index in a subsequent call to TlsGetValue, to retrieve the stored value.

TlsSetValue and TlsGetValue were implemented with speed as the primary goal. These functions perform minimal parameter validation and error checking. In particular, this function succeeds if dwTlsIndex is in the range 0 through (TLS_MINIMUM_AVAILABLE – 1). It is up to the programmer to ensure that the index is valid.

For example, see Using Thread Local Storage in a Dynamic-Link Library.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, TlsAlloc, TlsFree, TlsGetValue


UserHandleGrantAccess

The UserHandleGrantAccess function grants or denies access to a handle to a User object to a job that has a user-interface restriction. When access is granted, all processes associated with the job can subsequently recognize and use the handle. When access is denied, the processes can no longer use the handle. For more information see User Objects.

BOOL UserHandleGrantAccess(
  HANDLE hUserHandle,  // handle to User object
  HANDLE hJob,         // handle to job
  BOOL bGrant          // access granted or denied
);

Parameters

hUserHandle
[in] Handle to a User object.
hJob
[in] Handle to the job to be granted access to the User handle. The CreateJobObject or OpenJobObject function returns this handle.
bGrant
[in] Specifies whether access is to be denied or granted to hUserHandle. If bGrant is TRUE, all processes associated with the job can recognize and use the handle. If bGrant is FALSE, the processes can no longer use the handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The UserHandleGrantAccess function can be called only from a process not associated with the job specified by the hJob parameter. The User handle must not be owned by a process or thread associated with the job.

To create user-interface restrictions, call the SetInformationJobObject function with the JobObjectBasicUIRestrictions job information class.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateJobObject, OpenJobObject, SetInformationJobObject


WaitForInputIdle

The WaitForInputIdle function waits until the specified process is waiting for user input with no input pending, or until the time-out interval has elapsed.

DWORD WaitForInputIdle(
  HANDLE hProcess,       // handle to process
  DWORD dwMilliseconds   // time-out interval
);

Parameters

hProcess
[in] Handle to the process. If this process is a console application or does not have a message queue, WaitForInputIdle returns immediately.
dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. If dwMilliseconds is INFINITE, the function does not return until the process is idle.

Return Values

The following table shows the possible return values:

Value | Meaning
0 | The wait was satisfied successfully.
WAIT_TIMEOUT | The wait was terminated because the time-out interval elapsed.
WAIT_FAILED | An error occurred. To get extended error information, use the GetLastError function.

Remarks

The WaitForInputIdle function enables a thread to suspend its execution until the specified process has finished its initialization and is waiting for user input with no input pending. This can be useful for synchronizing a parent process and a newly created child process. When a parent process creates a child process, the CreateProcess function returns without waiting for the child process to finish its initialization. Before trying to communicate with the child process, the parent process can use WaitForInputIdle to determine when the child's initialization has been completed. For example, the parent process should use WaitForInputIdle before trying to find a window associated with the child process.

The WaitForInputIdle function can be used at any time, not just during application startup.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess


WinExec

The WinExec function runs the specified application.

Note This function is provided only for compatibility with 16-bit Windows. Win32-based applications should use the CreateProcess function.

UINT WinExec(
  LPCSTR lpCmdLine,  // command line
  UINT uCmdShow      // window style
);

Parameters

lpCmdLine
[in] Pointer to a null-terminated character string that contains the command line (file name plus optional parameters) for the application to be executed. If the name of the executable file in the lpCmdLine parameter does not contain a directory path, the system searches for the executable file in this sequence:
  1. The directory from which the application loaded.
  2. The current directory.
  3. The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.
  4. The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.
  5. The directories listed in the PATH environment variable.
uCmdShow
[in] Specifies how a Windows-based application window is to be shown and is used to supply the wShowWindow member of the STARTUPINFO parameter to the CreateProcess function. For a list of the acceptable values, see the description of the nCmdShow parameter of the ShowWindow function. For a non-Windows – based application, the PIF file, if any, for the application determines the window state.

Return Values

If the function succeeds, the return value is greater than 31.

If the function fails, the return value is one of the following error values:

Value | Meaning
0 | The system is out of memory or resources.
ERROR_BAD_FORMAT | The .exe file is invalid (non-Win32 .exe or error in .exe image).
ERROR_FILE_NOT_FOUND | The specified file was not found.
ERROR_PATH_NOT_FOUND | The specified path was not found.

Remarks

In Win32, the WinExec function returns when the started process calls the GetMessage function or a time-out limit is reached. To avoid waiting for the time out delay, call the GetMessage function as soon as possible in any process started by a call to WinExec.

Security Remarks

The executable name is treated as the first white space-delimited string in lpCmdLine. If the executable or path name has a space in it, there is a risk that a different executable could be run because of the way the function parses spaces. The following example is dangerous because the function will attempt to run "Program.exe", if it exists, instead of "MyApp.exe".

WinExec("C:\Program Files\MyApp", ...)

If a malicious user were to create an application called "Program.exe" on a system, any program that incorrectly calls WinExec using the Program Files directory will run this application instead of the intended application.

To avoid this problem, use CreateProcess rather than WinExec. However, if you must use WinExec for legacy reasons, make sure the application name is enclosed in quotation marks as shown in the example below.

WinExec("\"C:\Program Files\MyApp.exe\" -L -S", ...)

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Processes and Threads Overview, Process and Thread Functions, CreateProcess, GetMessage, GetSystemDirectory, GetWindowsDirectory, LoadModule, ShowWindow


Process and Thread Structures

The following structures are used with processes and threads.

IO_COUNTERS
PROCESS_INFORMATION
STARTUPINFO

Job Object Structures

The following structures are used with job objects.

JOBOBJECT_ASSOCIATE_COMPLETION_PORT
JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION
JOBOBJECT_BASIC_LIMIT_INFORMATION
JOBOBJECT_BASIC_PROCESS_ID_LIST
JOBOBJECT_BASIC_UI_RESTRICTIONS
JOBOBJECT_END_OF_JOB_TIME_INFORMATION
JOBOBJECT_EXTENDED_LIMIT_INFORMATION
JOBOBJECT_SECURITY_LIMIT_INFORMATION


IO_COUNTERS

The IO_COUNTERS structure contains I/O accounting information for a process or a job object. For a job object, the counters include all operations performed by all processes that have ever been associated with the job, in addition to all processes currently associated with the job.

typedef struct _IO_COUNTERS {
    ULONGLONG  ReadOperationCount;
    ULONGLONG  WriteOperationCount;
    ULONGLONG  OtherOperationCount;
    ULONGLONG ReadTransferCount;
    ULONGLONG WriteTransferCount;
    ULONGLONG OtherTransferCount;
} IO_COUNTERS;
typedef IO_COUNTERS *PIO_COUNTERS;

Members

ReadOperationCount
Specifies the number of read operations performed.
WriteOperationCount
Specifies the number of write operations performed.
OtherOperationCount
Specifies the number of I/O operations performed, other than read and write operations.
ReadTransferCount
Specifies the number of bytes read.
WriteTransferCount
Specifies the number of bytes written.
OtherTransferCount
Specifies the number of bytes transferred during operations other than read and write operations.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, GetProcessIoCounters, JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION


JOBOBJECT_ASSOCIATE_COMPLETION_PORT

The JOBOBJECT_ASSOCIATE_COMPLETION_PORT structure contains information used to associate a completion port with a job. You can associate one completion port with a job. There is no way to terminate the association and no way to associate a different port with the job.

typedef struct _JOBOBJECT_ASSOCIATE_COMPLETION_PORT {
    PVOID CompletionKey;
    HANDLE CompletionPort;
} JOBOBJECT_ASSOCIATE_COMPLETION_PORT, PJOBOBJECT_ASSOCIATE_COMPLETION_PORT;

Members

CompletionKey
Specifies the value to use in the dwCompletionKey parameter of PostQueuedCompletionStatus when messages are sent on behalf of the job.
CompletionPort
Specifies the completion port to use in the CompletionPort parameter of the PostQueuedCompletionStatus function when messages are sent on behalf of the job.

Remarks

The job sends messages to the completion port when certain events occur. All messages are sent directly from the job as if the job had called the PostQueuedCompletionStatus function. A thread monitoring the completion port using the GetQueuedCompletionStatus function must pick up the messages. The thread receives information in the GetQueuedCompletionStatus parameters shown in the following table.

Parameter | Information Received
lpCompletionKey | The value specified in CompletionKey during the completion-port association. If a completion port is associated with multiple jobs, CompletionKey should help the caller determine which completion port is sending a message.
lpOverlapped | Message-specific value. For more information, see the following table of message identifiers.
LpNumberOfBytesTransfered | The message identifier that indicates which job-related event occurred. For more information, see the following table of message identifiers.

The following messages can be sent to the completion port.

Message Identifier | Description
JOB_OBJECT_MSG_END_OF_JOB_TIME | Indicates that the JOB_OBJECT_POST_AT_END_OF_JOB option is in effect and the end-of-job time limit has been reached. Upon posting this message, the time limit is canceled and the job's processes can continue to run. The value of lpOverlapped is NULL.
JOB_OBJECT_MSG_END_OF_PROCESS_TIME | Indicates that a process has exceeded a per-process time limit. The system sends this message after the process termination has been requested. The value of lpOverlapped is the identifier of the process that exceeded its limit.
JOB_OBJECT_MSG_ACTIVE_PROCESS_LIMIT | Indicates that the active process limit has been exceeded. The value of lpOverlapped is NULL.
JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO | Indicates that the active process count has been decremented to 0. For example, if the job currently has two active processes, the system sends this message after they both terminate. The value of lpOverlapped is NULL.
JOB_OBJECT_MSG_NEW_PROCESS | Indicates that a process has been added to the job. Processes added to a job at the time a completion port is associated are also reported. The value of lpOverlapped is the identifier of the process added to the job.
JOB_OBJECT_MSG_EXIT_PROCESS | Indicates that a process associated with the job has exited. The value of lpOverlapped is the identifier of the exiting process.
JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS | Indicates that a process associated with the job exited with an exit code that indicates an abnormal exit (see the list following this table). The value of lpOverlapped is the identifier of the exiting process.
JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT | Indicates that a process associated with the job has exceeded its memory limit (if one is in effect). The value of lpOverlapped is the identifier of the process that has exceeded its limit. The system does not send this message if the process has not yet reported its process identifier.
JOB_OBJECT_MSG_JOB_MEMORY_LIMIT | Indicates that a process associated with the job caused the job to exceed the job-wide memory limit (if one is in effect). The value of lpOverlapped specifies the identifier of the process that has attempted to exceed the limit. The system does not send this message if the process has not yet reported its process identifier.

The following exit codes indicate an abnormal exit:

STATUS_ACCESS_VIOLATION
STATUS_ARRAY_BOUNDS_EXCEEDED
STATUS_BREAKPOINT
STATUS_CONTROL_C_EXIT
STATUS_DATATYPE_MISALIGNMENT
STATUS_FLOAT_DENORMAL_OPERAND
STATUS_FLOAT_DIVIDE_BY_ZERO
STATUS_FLOAT_INEXACT_RESULT
STATUS_FLOAT_INVALID_OPERATION
STATUS_FLOAT_MULTIPLE_FAULTS
STATUS_FLOAT_MULTIPLE_TRAPS
STATUS_FLOAT_OVERFLOW
STATUS_FLOAT_STACK_CHECK
STATUS_FLOAT_UNDERFLOW
STATUS_GUARD_PAGE_VIOLATION
STATUS_ILLEGAL_INSTRUCTION
STATUS_IN_PAGE_ERROR
STATUS_INVALID_DISPOSITION
STATUS_INTEGER_DIVIDE_BY_ZERO
STATUS_INTEGER_OVERFLOW
STATUS_NONCONTINUABLE_EXCEPTION
STATUS_PRIVILEGED_INSTRUCTION
STATUS_REG_NAT_CONSUMPTION
STATUS_SINGLE_STEP
STATUS_STACK_OVERFLOW

You must be cautious when using the JOB_OBJECT_MSG_NEW_PROCESS and JOB_OBJECT_MSG_EXIT_PROCESS messages, as race conditions may occur. For instance, if processes are actively starting and exiting within a job, and you are in the process of assigning a completion port to the job, you may miss messages for processes whose states change during the association of the completion port. For this reason, it is best to associate a completion port with a job when the job is inactive.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, PostQueuedCompletionStatus, QueryInformationJobObject, SetInformationJobObject


JOBOBJECT_BASIC_ACCOUNTING_INFORMATION

The JOBOBJECT_BASIC_ACCOUNTING_INFORMATION structure contains basic accounting information for a job object.

typedef struct _JOBOBJECT_BASIC_ACCOUNTING_INFORMATION {
    LARGE_INTEGER TotalUserTime;
    LARGE_INTEGER TotalKernelTime;
    LARGE_INTEGER ThisPeriodTotalUserTime;
    LARGE_INTEGER ThisPeriodTotalKernelTime;
    DWORD TotalPageFaultCount;
    DWORD TotalProcesses;
    DWORD ActiveProcesses;
    DWORD TotalTerminatedProcesses;
} JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, *PJOBOBJECT_BASIC_ACCOUNTING_INFORMATION;

Members

TotalUserTime
Specifies the total amount of user-mode execution time, in 100-nanosecond ticks, for all active processes associated with the job, as well as all terminated processes no longer associated with the job.
TotalKernelTime
Specifies the total amount of kernel-mode execution time, in 100-nanosecond ticks, for all active processes associated with the job, as well as all terminated processes no longer associated with the job.
ThisPeriodTotalUserTime
Specifies the total amount of user-mode execution time, in 100-nanosecond ticks, for all active processes associated with the job (as well as all terminated processes no longer associated with the job) since the last call that set a per-job user-mode time limit.

This member is set to 0 on creation of the job, and each time a per-job user-mode time limit is established.

ThisPeriodTotalKernelTime
Specifies the total amount of kernel-mode execution time, in 100-nanosecond ticks, for all active processes associated with the job (as well as all terminated processes no longer associated with the job) since the last call that set a per-job kernel-mode time limit.

This member is set to 0 on creation of the job, and each time a per-job kernel-mode time limit is established.

TotalPageFaultCount
Specifies the total number of page faults encountered by all active processes associated with the job, as well as all terminated processes no longer associated with the job.
TotalProcesses
Specifies the total number of processes associated with the job during its lifetime, including those that have terminated. For example, when a process is associated with a job, but the association fails because of a limit violation, this value is incremented.
ActiveProcesses
Specifies the total number of processes currently associated with the job. When a process is associated with a job, but the association fails because of a limit violation, this value is temporarily incremented. When the terminated process exits and all references to the process are released, this value is decremented.
TotalTerminatedProcesses
Specifies the total number of processes terminated because of a limit violation.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, QueryInformationJobObject, SetInformationJobObject


JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION

The JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION structure contains basic accounting and I/O accounting information for a job object.

typedef struct JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION {
    JOBOBJECT_BASIC_ACCOUNTING_INFORMATION BasicInfo;
    IO_COUNTERS IoInfo;
} JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION, *PJOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION;

Members

BasicInfo
A JOBOBJECT_BASIC_ACCOUNTING_INFORMATION structure that specifies the basic accounting information for the job.
IoInfo
An IO_COUNTERS structure that specifies the I/O accounting information for the job. The structure includes information for all processes that have ever been associated with the job, in addition to the information for all processes currently associated with the job.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, IO_COUNTERS, JOBOBJECT_BASIC_ACCOUNTING_INFORMATION, QueryInformationJobObject


JOBOBJECT_BASIC_LIMIT_INFORMATION

The JOBOBJECT_BASIC_LIMIT_INFORMATION structure contains basic limit information for a job object.

typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION {
    LARGE_INTEGER PerProcessUserTimeLimit;
    LARGE_INTEGER PerJobUserTimeLimit;
    DWORD LimitFlags;
    SIZE_T MinimumWorkingSetSize;
    SIZE_T MaximumWorkingSetSize;
    DWORD ActiveProcessLimit;
    ULONG_PTR Affinity;
    DWORD PriorityClass;
    DWORD SchedulingClass;
} JOBOBJECT_BASIC_LIMIT_INFORMATION, *PJOBOBJECT_BASIC_LIMIT_INFORMATION;

Members

PerProcessUserTimeLimit
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_PROCESS_TIME. Specifies the per-process user-mode execution time limit, in 100-nanosecond ticks.

The system periodically checks to determine whether each process associated with the job has accumulated more user-mode time than the set limit. If it has, the process is terminated.

PerJobUserTimeLimit
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_JOB_TIME. Specifies the per-job user-mode execution time limit, in 100-nanosecond ticks. The system adds the current time of the processes associated with the job to this limit. For example, if you set this limit to 1 minute, and the job has a process that has accumulated 5 minutes of user-mode time, the limit actually enforced is 6 minutes.

The system periodically checks to determine whether the sum of the user-mode execution time for all processes is greater than this end-of-job limit. If it is, the action specified in the EndOfJobTimeAction member of the JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure is carried out. By default, all processes are terminated and the status code is set to ERROR_NOT_ENOUGH_QUOTA.

LimitFlags
Specifies the limit flags that are in effect. This member is a bit field that determines whether other structure members are used. Any combination of the following values can be specified.
Value | Meaning
JOB_OBJECT_LIMIT_ACTIVE_PROCESS | Establishes a maximum number of simultaneously active processes associated with the job.
JOB_OBJECT_LIMIT_AFFINITY | Causes all processes associated with the job to use the same processor affinity.
JOB_OBJECT_LIMIT_BREAKAWAY_OK If any process associated with the job creates a child process using the CREATE_BREAKAWAY_FROM_JOB flag while this limit is in effect, the child process is not associated with the job.

This limit requires use of a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. The BasicLimitInformation member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.

JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION Forces a call to the SetErrorMode function with the SEM_NOGPFAULTERRORBOX flag for each process associated with the job.

If an exception occurs and the system calls the UnhandledExceptionFilter function, the debugger will be given a chance to act. If there is no debugger, the functions returns EXCEPTION_EXECUTE_HANDLER. Normally, this will cause termination of the process with the exception code as the exit status.

JOB_OBJECT_LIMIT_JOB_MEMORY | Causes all processes associated with the job to limit the job-wide sum of their committed memory. When a process attempts to commit memory that would exceed the job-wide limit, it fails. If the job object is associated with a completion port, a JOB_OBJECT_MSG_JOB_MEMORY_LIMIT message is sent to the completion port.
JOB_OBJECT_LIMIT_JOB_TIME | Establishes a user-mode execution time limit for the job. This flag cannot be used with JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME.
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | Causes all processes associated with the job to terminate when the last handle to the job is closed.
JOB_OBJECT_LIMIT_PRIORITY_CLASS | Causes all processes associated with the job to use the same priority class. For more information, see Scheduling Priorities.
JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME | Preserves any job time limits you previously set. As long as this flag is set, you can establish a per-job time limit once, then alter other limits in subsequent calls. This flag cannot be used with JOB_OBJECT_LIMIT_JOB_TIME.
JOB_OBJECT_LIMIT_PROCESS_MEMORY | Causes all processes associated with the job to limit their committed memory. When a process attempts to commit memory that would exceed the per-process limit, it fails. If the job object is associated with a completion port, a JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT message is sent to the completion port.
JOB_OBJECT_LIMIT_PROCESS_TIME | Establishes a user-mode execution time limit for each currently active process and for all future processes associated with the job.
JOB_OBJECT_LIMIT_SCHEDULING_CLASS | Causes all processes in the job to use the same scheduling class.
JOB_OBJECT_LIMIT_WORKINGSET | Causes all processes associated with the job to use the same minimum and maximum working set sizes.
JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK Allows any process associated with the job to create child processes that are not associated with the job.

This limit requires use of a JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure. The BasicLimitInformation member is a JOBOBJECT_BASIC_LIMIT_INFORMATION structure.

MinimumWorkingSetSize
Ignored unless the LimitFlags member specifies JOB_OBJECT_LIMIT_WORKINGSET. Specifies the minimum working set size for all processes associated with the job.
MaximumWorkingSetSize
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_WORKINGSET. Specifies the maximum working set size for all processes associated with the job.
ActiveProcessLimit
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_ACTIVE_PROCESS. Specifies the active process limit for the job. If you try to associate a process with a job, and this causes the active process count to exceed this limit, the process is terminated and the association fails.
Affinity
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_AFFINITY. Specifies the processor affinity for all processes associated with the job. The affinity must be a proper subset of the system affinity mask obtained by calling the GetProcessAffinityMask function. The affinity of each thread is set to this value, but threads are free to subsequently set their affinity, as long as it is a subset of the specified affinity mask. Processes cannot set their own affinity mask.
PriorityClass
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_PRIORITY_CLASS. Specifies the priority class for all processes associated with the job. Processes and threads cannot modify their priority class. The calling process must enable the SE_INC_BASE_PRIORITY_NAME privilege.
SchedulingClass
Ignored unless LimitFlags specifies JOB_OBJECT_LIMIT_SCHEDULING_CLASS. Specifies the scheduling class for all processes associated with the job.

The valid values are 0 to 9. Use 0 for the least favorable scheduling class relative to other threads, and 9 for the most favorable scheduling class relative to other threads. By default, this value is 5. To use a scheduling class greater than 5, the calling process must enable the SE_INC_BASE_PRIORITY_NAME privilege.

Remarks

Processes can still empty their working sets using the SetProcessWorkingSetSize function, even when JOB_OBJECT_LIMIT_WORKINGSET is used. However, you cannot use SetProcessWorkingSetSize to change the minimum or maximum working set size.

The system increments the active process count when you attempt to associate a process with a job. If the limit is exceeded, the system decrements the active process count only when the process terminates and all handles to the process are closed. Therefore, if you have an open handle to a process that has been terminated in such a manner, you cannot associate any new processes until the handle is closed and the active process count is below the limit.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, GetProcessAffinityMask, JOBOBJECT_END_OF_JOB_TIME_INFORMATION, JOBOBJECT_EXTENDED_LIMIT_INFORMATION QueryInformationJobObject, SetInformationJobObject, SetProcessWorkingSetSize


JOBOBJECT_BASIC_PROCESS_ID_LIST

The JOBOBJECT_BASIC_PROCESS_ID_LIST structure contains the process identifier list for a job object.

typedef struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {
    DWORD NumberOfAssignedProcesses;
    DWORD NumberOfProcessIdsInList;
    ULONG_PTR ProcessIdList[1];
} JOBOBJECT_BASIC_PROCESS_ID_LIST, *PJOBOBJECT_BASIC_PROCESS_ID_LIST;

Members

NumberOfAssignedProcesses
Specifies the number of process identifiers to be stored in ProcessIdList.
NumberOfProcessIdsInList
Specifies the number of process identifiers returned in the ProcessIdList buffer. If this number is less than NumberOfAssignedProcesses, increase the size of the buffer to accommodate the complete list.
ProcessIdList
Specifies the variable-length array of process identifiers returned by this call. Array elements 0 through NumberOfProcessIdsInList – 1 contain valid process identifiers.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, QueryInformationJobObject, SetInformationJobObject


JOBOBJECT_BASIC_UI_RESTRICTIONS

The JOBOBJECT_BASIC_UI_RESTRICTIONS structure contains basic user-interface restrictions for a job object.

typedef struct _JOBOBJECT_BASIC_UI_RESTRICTIONS {
    DWORD UIRestrictionsClass;
} JOBOBJECT_BASIC_UI_RESTRICTIONS, *PJOBOBJECT_BASIC_UI_RESTRICTIONS;

Members

UIRestrictionsClass
Specifies the restriction class for the user interface. This member can be one or more of the following values.
Value | Meaning
JOB_OBJECT_UILIMIT_DESKTOP | Prevents processes associated with the job from creating desktops and switching desktops using the CreateDesktop and SwitchDesktop functions.
JOB_OBJECT_UILIMIT_DISPLAYSETTINGS | Prevents processes associated with the job from calling the ChangeDisplaySettings function.
JOB_OBJECT_UILIMIT_EXITWINDOWS | Prevents processes associated with the job from calling the ExitWindows or ExitWindowsEx function.
JOB_OBJECT_UILIMIT_GLOBALATOMS | Prevents processes associated with the job from accessing global atoms. When this flag is used, each job has its own atom table.
JOB_OBJECT_UILIMIT_HANDLES | Prevents processes associated with the job from using USER handles owned by processes not associated with the same job.
JOB_OBJECT_UILIMIT_READCLIPBOARD | Prevents processes associated with the job from reading data from the clipboard.
JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS | Prevents processes associated with the job from changing system parameters by using the SystemParametersInfo function.
JOB_OBJECT_UILIMIT_WRITECLIPBOARD | Prevents processes associated with the job from writing data to the clipboard.

Remarks

If you specify the JOB_OBJECT_UILIMIT_HANDLES flag, when a process associated with the job broadcasts messages, they are only sent to top-level windows owned by processes associated with the same job. In addition, hooks can be installed only on threads belonging to processes associated with the job.

To grant access to a User handle to a job that has a user-interface restriction, use the UserHandleGrantAccess function.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, ExitWindows, ExitWindowsEx QueryInformationJobObject, SetInformationJobObject, SystemParametersInfo, UserHandleGrantAccess


JOBOBJECT_END_OF_JOB_TIME_INFORMATION

The JOBOBJECT_END_OF_JOB_TIME_INFORMATION structure specifies the action the system will perform when an end-of-job time limit is exceeded.

typedef struct _JOBOBJECT_END_OF_JOB_TIME_INFORMATION {
    DWORD EndOfJobTimeAction;
} JOBOBJECT_END_OF_JOB_TIME_INFORMATION, PJOBOBJECT_END_OF_JOB_TIME_INFORMATION;

Members

EndOfJobTimeAction
Specifies the action that the system will perform when the end-of-job time limit has been exceeded. This member can be one of the following values.
Value Meaning
JOB_OBJECT_TERMINATE_AT_END_OF_JOB Terminates all processes and sets the exit status to ERROR_NOT_ENOUGH_QUOTA. The processes cannot prevent or delay their own termination. The job object is set to the signaled state and remains signaled until this limit is reset. No additional processes can be assigned to the job until the limit is reset.

This is the default termination action.
JOB_OBJECT_POST_AT_END_OF_JOB Posts a completion packet to the completion port using the PostQueuedCompletionStatus function. After the completion packet is posted, the system clears the end-of-job time limit, and processes in the job can continue their execution.

If no completion port is associated with the job when the time limit has been exceeded, the action taken is the same as for JOB_OBJECT_TERMINATE_AT_END_OF_JOB.

Remarks

The end-of-job time limit is specified in the PerJobUserTimeLimit member of the JOBOBJECT_BASIC_LIMIT_INFORMATION structure.

To associate a completion port with a job, use the JOBOBJECT_ASSOCIATE_COMPLETION_PORT structure.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, JOBOBJECT_ASSOCIATE_COMPLETION_PORT, JOBOBJECT_BASIC_LIMIT_INFORMATION, PostQueuedCompletionStatus, QueryInformationJobObject, SetInformationJobObject


JOBOBJECT_EXTENDED_LIMIT_INFORMATION

The JOBOBJECT_EXTENDED_LIMIT_INFORMATION structure contains basic and extended limit information for a job object.

typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
    JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
    IO_COUNTERS IoInfo;
    SIZE_T ProcessMemoryLimit;
    SIZE_T JobMemoryLimit;
    SIZE_T PeakProcessMemoryUsed;
    SIZE_T PeakJobMemoryUsed;
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;

Members

BasicLimitInformation
A JOBOBJECT_BASIC_LIMIT_INFORMATION structure that contains basic limit information.
IoInfo
Reserved.
ProcessMemoryLimit
Ignored unless the LimitFlags member of the JOBOBJECT_BASIC_LIMIT_INFORMATION structure specifies the JOB_OBJECT_LIMIT_PROCESS_MEMORY value. Specifies the per-process memory limit.
JobMemoryLimit
Ignored unless the LimitFlags member of the JOBOBJECT_BASIC_LIMIT_INFORMATION structure specifies the JOB_OBJECT_LIMIT_JOB_MEMORY value. Specifies the per-job memory limit.
PeakProcessMemoryUsed
Specifies the most process memory used by any process ever associated with the job.
PeakJobMemoryUsed
Specifies the peak memory usage of all processes associated with the job.

Remarks

The system tracks the value of PeakProcessMemoryUsed and PeakJobMemoryUsed constantly. This allows you know the peak memory usage of each job. You can use this information to establish a memory limit using the JOB_OBJECT_LIMIT_PROCESS_MEMORY or JOB_OBJECT_LIMIT_JOB_MEMORY value.

Note that the job memory and process memory limits are very similar in operation, but they are independent. You could set a job-wide limit of 100 MB with a per-process limit of 10 MB. In this scenario, no single process could commit more than 10 MB, and the set of processes associated with a job could never exceed 100 MB.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, JOBOBJECT_BASIC_LIMIT_INFORMATION, QueryInformationJobObject, SetInformationJobObject


JOBOBJECT_SECURITY_LIMIT_INFORMATION

The JOBOBJECT_SECURITY_LIMIT_INFORMATION structure contains the security limitations for a job object.

typedef struct _JOBOBJECT_SECURITY_LIMIT_INFORMATION {
    DWORD SecurityLimitFlags ;
    HANDLE JobToken ;
    PTOKEN_GROUPS SidsToDisable ;
    PTOKEN_PRIVILEGES PrivilegesToDelete ;
    PTOKEN_GROUPS RestrictedSids ;
} JOBOBJECT_SECURITY_LIMIT_INFORMATION, *PJOBOBJECT_SECURITY_LIMIT_INFORMATION ;

Members

SecurityLimitFlags
Specifies the security limitations for the job. This member can be one or more of the following values.
Value | Meaning
JOB_OBJECT_SECURITY_NO_ADMIN | Prevents any process in the job from using a token that specifies the local administrators group.
JOB_OBJECT_SECURITY_RESTRICTED_TOKEN | Prevents any process in the job from using a token that was not created with the CreateRestrictedToken function.
JOB_OBJECT_SECURITY_ONLY_TOKEN | Forces processes in the job to run under a specific token. Requires a token handle in the JobToken member.
JOB_OBJECT_SECURITY_FILTER_TOKENS | Applies a filter to the token when a process impersonates a client. Requires at least one of the following members to be set: SidsToDisable, PrivilegesToDelete, or RestrictedSids.

JobToken
Handle to a primary token that represents a user. The handle must have TOKEN_ASSIGN_PRIMARY access.

If the token was created with CreateRestrictedToken, all processes in the job are limited to that token or a further restricted token. Otherwise, the caller must have the SE_ASSIGNPRIMARYTOKEN_NAME privilege.

SidsToDisable
Pointer to a TOKEN_GROUPS structure that specifies the SIDs to disable for access checking, if SecurityLimitFlags is JOB_OBJECT_SECURITY_FILTER_TOKENS.

This member can be NULL if you do not want to disable any SIDs.

PrivilegesToDelete
Pointer to a TOKEN_PRIVILEGES structure that specifies the privileges to delete from the token, if SecurityLimitFlags is JOB_OBJECT_SECURITY_FILTER_TOKENS.

This member can be NULL if you do not want to delete any privileges.

RestrictedSids
Pointer to a TOKEN_GROUPS structure that specifies the deny-only SIDs that will be added to the access token, if SecurityLimitFlags is JOB_OBJECT_SECURITY_FILTER_TOKENS.

This member can be NULL if you do not want to specify any deny-only SIDs.

Remarks

After security limitations are placed on processes in a job, they cannot be revoked.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, CreateRestrictedToken, QueryInformationJobObject, SetInformationJobObject, TOKEN_GROUPS, TOKEN_PRIVILEGES


PROCESS_INFORMATION

The PROCESS_INFORMATION structure is filled in by the CreateProcess function with information about a newly created process and its primary thread.

typedef struct _PROCESS_INFORMATION {
    HANDLE hProcess;
    HANDLE hThread;
    DWORD dwProcessId;
    DWORD dwThreadId;
} PROCESS_INFORMATION;

Members

hProcess
A handle to the newly created process. The handle is used to specify the process in all functions that perform operations on the process object.
hThread
A handle to the primary thread of the newly created process. The handle is used to specify the thread in all functions that perform operations on the thread object.
dwProcessId
A global process identifier that can be used to identify a process. The value is valid from the time the process is created until the time the process is terminated.
dwThreadId
A global thread identifiers that can be used to identify a thread. The value is valid from the time the thread is created until the time the thread is terminated.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Structures, CreateProcess


STARTUPINFO

The STARTUPINFO structure is used with the CreateProcess function to specify main window properties if a new window is created for the new process. For graphical user interface (GUI) processes, this information affects the first window created by the CreateWindow function and shown by the ShowWindow function. For console processes, this information affects the console window if a new console is created for the process. A process can use the GetStartupInfo function to retrieve the STARTUPINFO structure specified when the process was created.

typedef struct _STARTUPINFO {
    DWORD   cb;
    LPTSTR  lpReserved;
    LPTSTR  lpDesktop;
    LPTSTR  lpTitle;
    DWORD   dwX;
    DWORD   dwY;
    DWORD   dwXSize;
    DWORD   dwYSize;
    DWORD   dwXCountChars;
    DWORD   dwYCountChars;
    DWORD   dwFillAttribute;
    DWORD   dwFlags;
    WORD    wShowWindow;
    WORD    cbReserved2;
    LPBYTE  lpReserved2;
    HANDLE  hStdInput;
    HANDLE  hStdOutput;
    HANDLE  hStdError;
} STARTUPINFO, *LPSTARTUPINFO;

Members

cb
Specifies the size, in bytes, of the structure.
lpReserved
Reserved. Set this member to NULL before passing the structure to CreateProcess.
lpDesktop
Windows NT/2000 or later: Pointer to a null-terminated string that specifies either the name of the desktop only or the name of both the desktop and window station for this process. A backslash in the string pointed to by lpDesktop indicates that the string includes both desktop and window station names. If lpDesktop is NULL, the new process inherits the desktop and window station of its parent process. If lpDesktop is an empty string, the process does not inherit the desktop and window station of its parent process; instead, the system determines if a new desktop and window station need to be created. If the impersonated user already has a desktop, the system will use the existing desktop.
lpTitle
For console processes, this is the title displayed in the title bar if a new console window is created. If NULL, the name of the executable file is used as the window title instead. This parameter must be NULL for GUI or console processes that do not create a new console window.
dwX
Ignored unless dwFlags specifies STARTF_USEPOSITION. Specifies the x offset, in pixels, of the upper left corner of a window if a new window is created. The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new process calls CreateWindow to create an overlapped window if the x parameter of CreateWindow is CW_USEDEFAULT.
dwY
Ignored unless dwFlags specifies STARTF_USEPOSITION. Specifies the y offset, in pixels, of the upper left corner of a window if a new window is created. The offset is from the upper left corner of the screen. For GUI processes, the specified position is used the first time the new process calls CreateWindow to create an overlapped window if the y parameter of CreateWindow is CW_USEDEFAULT.
dwXSize
Ignored unless dwFlags specifies STARTF_USESIZE. Specifies the width, in pixels, of the window if a new window is created. For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the nWidth parameter of CreateWindow is CW_USEDEFAULT.
dwYSize
Ignored unless dwFlags specifies STARTF_USESIZE. Specifies the height, in pixels, of the window if a new window is created. For GUI processes, this is used only the first time the new process calls CreateWindow to create an overlapped window if the nHeight parameter of CreateWindow is CW_USEDEFAULT.
dwXCountChars
Windows NT/2000 or later: Ignored unless dwFlags specifies STARTF_USECOUNTCHARS. For console processes, if a new console window is created, dwXCountChars specifies the screen buffer width in character columns. This value is ignored in a GUI process and on Windows 95/98/Me.
dwYCountChars
Windows NT/2000 or later: Ignored unless dwFlags specifies STARTF_USECOUNTCHARS. For console processes, if a new console window is created, dwYCountChars specifies the screen buffer height in character rows. This value is ignored in a GUI process and on Windows 95/98/Me.
dwFillAttribute
Ignored unless dwFlags specifies STARTF_USEFILLATTRIBUTE. Specifies the initial text and background colors if a new console window is created in a console application. These values are ignored in GUI applications. This value can be any combination of the following values: FOREGROUND_BLUE, FOREGROUND_GREEN, FOREGROUND_RED, FOREGROUND_INTENSITY, BACKGROUND_BLUE, BACKGROUND_GREEN, BACKGROUND_RED, and BACKGROUND_INTENSITY. For example, the following combination of values produces red text on a white background:
FOREGROUND_RED| BACKGROUND_RED| BACKGROUND_GREEN| BACKGROUND_BLUE
dwFlags
This is a bit field that determines whether certain STARTUPINFO members are used when the process creates a window. Any combination of the following values can be specified:
Value | Meaning
STARTF_FORCEONFEEDBACK | Indicates that the cursor is in feedback mode for two seconds after CreateProcess is called. If during those two seconds the process makes the first GUI call, the system gives five more seconds to the process. If during those five seconds the process shows a window, the system gives five more seconds to the process to finish drawing the window.
The system turns the feedback cursor off after the first call to GetMessage, regardless of whether the process is drawing.
STARTF_FORCEOFFFEEDBACK | Indicates that the feedback cursor is forced off while the process is starting. The normal cursor is displayed.
STARTF_RUNFULLSCREEN Windows NT/2000 or later: Indicates that the process should be run in full-screen mode, rather than in windowed mode.

This flag is only valid for console applications running on an x86 computer.
STARTF_USECOUNTCHARS | Windows NT/2000 or later: If this value is not specified, the dwXCountChars and dwYCountChars members are ignored.
STARTF_USEFILLATTRIBUTE | If this value is not specified, the dwFillAttribute member is ignored.
STARTF_USEPOSITION | If this value is not specified, the dwX and dwY members are ignored.
STARTF_USESHOWWINDOW | If this value is not specified, the wShowWindow member is ignored.
STARTF_USESIZE | If this value is not specified, the dwXSize and dwYSize members are ignored.
STARTF_USESTDHANDLES | Sets the standard input, standard output, and standard error handles for the process to the handles specified in the hStdInput, hStdOutput, and hStdError members of the STARTUPINFO structure. The CreateProcess function's fInheritHandles parameter must be set to TRUE for this to work properly.
If this value is not specified, the hStdInput, hStdOutput, and hStdError members of the STARTUPINFO structure are ignored.

wShowWindow
Ignored unless dwFlags specifies STARTF_USESHOWWINDOW. The wShowWindow member can be any of the SW_ constants defined in WINUSER.H. For GUI processes, wShowWindow specifies the default value the first time ShowWindow is called. The nCmdShow parameter of ShowWindow is ignored. In subsequent calls to ShowWindow, the wShowWindow member is used if the nCmdShow parameter of ShowWindow is set to SW_SHOWDEFAULT.
cbReserved2
Reserved; must be zero.
lpReserved2
Reserved; must be NULL.
hStdInput
Ignored unless dwFlags specifies STARTF_USESTDHANDLES. Specifies a handle that will be used as the standard input handle to the process if STARTF_USESTDHANDLES is specified.
hStdOutput
Ignored unless dwFlags specifies STARTF_USESTDHANDLES. Specifies a handle that will be used as the standard output handle to the process if STARTF_USESTDHANDLES is specified.
hStdError
Ignored unless dwFlags specifies STARTF_USESTDHANDLES. Specifies a handle that will be used as the standard error handle to the process if STARTF_USESTDHANDLES is specified.

Remarks

If a GUI process is being started and neither STARTF_FORCEONFEEDBACK or STARTF_FORCEOFFFEEDBACK is specified, the process feedback cursor is used. A GUI process is one whose subsystem is specified as "windows."

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Processes and Threads Overview, Process and Thread Structures, CreateProcess, CreateProcessAsUser, CreateWindow, GetMessage, GetStartupInfo, PeekMessage, ShowWindow, WinMain


Process and Thread Macros

The following macros are used with fibers.

GetCurrentFiber
GetFiberData


GetCurrentFiber

The GetCurrentFiber macro returns the address of the current fiber.

PVOID GetCurrentFiber(VOID);

Parameters

This macro has no parameters.

Return Values

The return value is the address of the currently running fiber.

Remarks

The CreateFiber and ConvertThreadToFiber functions return the fiber address when the fiber is created. The GetCurrentFiber macro allows you to retrieve the address at any other time.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Macros, CreateFiber, ConvertThreadToFiber


GetFiberData

The GetFiberData macro returns the fiber data associated with the current fiber.

PVOID GetFiberData(VOID);

Parameters

This macro has no parameters.

Return Values

The return value is the fiber data for the currently running fiber.

Remarks

The fiber data is the value passed to the CreateFiber or ConvertThreadToFiber functions in the lpParameter parameter. This value is also received as the parameter to the fiber function. It is stored as part of the fiber state information.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.51 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winnt.h; include Windows.h.

See Also

Processes and Threads Overview, Process and Thread Macros, CreateFiber, ConvertThreadToFiber


Services

Microsoft® Windows NT®/Windows® 2000 supports an application type known as a service. A service application conforms to the interface rules of the Service Control Manager (SCM). It can be started automatically at system boot, by a user through the Services control panel applet, or by an application that uses the service functions included in the Microsoft® Win32® application programming interface (API). Services can execute even when no user is logged on to the system.

Windows NT/Windows 2000 also supports a driver service, which conforms to the device driver protocols for Windows NT/Windows 2000. It is similar to the service application, but it does not interact with the SCM. For simplicity, the term service refers to a service application in this overview.

  • About Services
  • Using Services
  • Service Reference

Note Windows 95/98/Me supports a subset of the functionality provided by the SCM. For more information, see Windows 95/98/Me Service Control Manager.


About Services

The Service Control Manager (SCM) maintains a database of installed services and driver services, and provides a unified and secure means of controlling them. The database includes information on how each service or driver service should be started. It also enables system administrators to customize security requirements for each service and thereby control access to the service.

The following types of programs use the functions provided by the SCM.

Type | Description
Service Programs | A program that provides executable code for one or more services. Service programs use functions that connect to the SCM and send status information to the SCM.
Service Configuration Program | A program that queries or modifies the services database. Service configuration programs use functions that open the database, install or delete services in the database, and query or modify the configuration and security parameters for installed services. Service configuration programs manage both services and driver services.
Service Control Program | A program that starts and controls services and driver services. Service control programs use functions that send requests to the SCM, which carries out the request.

This overview discusses the following topics:

  • Service Control Manager
  • Service Programs
  • Service Configuration Programs
  • Service Control Programs
  • Service Security
  • Interactive Services
  • Debugging a Service


Service Control Manager

The service control manager (SCM) is started at system boot. It is a remote procedure call (RPC) server, so that service configuration and service control programs can manipulate services on remote machines.

The Win32 API includes a set of functions that provide an interface for the following tasks performed by the SCM:

  • Maintaining the database of installed services.
  • Starting services and driver services either upon system startup or upon demand.
  • Enumerating installed services and driver services.
  • Maintaining status information for running services and driver services.
  • Transmitting control requests to running services.
  • Locking and unlocking the service database.

The following sections describe the SCM in more detail:

  • Database of Installed Services
  • Automatically Starting Services
  • Starting Services on Demand
  • Service Record List
  • SCM Handles


Database of Installed Services

The SCM maintains a database of installed services in the registry. The database is used by the SCM and programs that add, modify, or configure services. The following is the registry key for this database.

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

This key contains a subkey for each installed service and driver service. The name of the subkey is the name of the service, as specified by the CreateService function when the service was installed by a service configuration program.

An initial copy of the database is created during Windows NT/Windows 2000 setup. The database contains entries for the device drivers required during system boot. The database includes the following information about each installed service and driver service:

  • The service type. This indicates whether the service executes in its own process or shares a process with other services. For driver services, this indicates whether the service is a kernel driver or a file system driver.
  • The start type. This indicates whether the service or driver service is started automatically at system startup (auto-start service) or whether the SCM starts it when requested by a service control program (demand-start service). The start type can also indicate that the service or driver service is disabled, in which case it cannot be started.
  • The error control level. This specifies the severity of the error if the service or driver service fails to start during system startup and determines the action that the startup program will take.
  • The fully qualified path of the executable file. The filename extension is .EXE for services and .SYS for driver services.
  • Optional dependency information used to determine the proper order for starting services or driver services. For services, this information can include a list of services that the SCM must start before it can start the specified service, the name of a load ordering group that the service is part of, and a tag identifier that indicates the start order of the service in its load ordering group. For driver services, this information includes a list of drivers that must be started before the specified driver.
  • For services, an optional account name and password. The service program runs in the context of this account. If no account is specified, the service executes in the context of the LocalSystem account.
  • For driver services, an optional driver object name (for example, \FileSystem\Rdr or \Driver\Xns), used by the I/O system to load the device driver. If no name is specified, the I/O system creates a default name based on the driver service name.

Note This database is also known as the ServicesActive database or the SCM database. You must use the functions provided by the SCM, instead of modifying the database directly.


Automatically Starting Services

During system boot, the SCM starts all auto-start services and the services on which they depend. For example, if an auto-start service depends on a demand-start service, the demand-start service is also started automatically. The load order is determined by the following:

  1. The order of groups in the load ordering group list, ServiceGroupOrder, in the following registry key:

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

  2. The order of services within a group specified in the tags order vector, GroupOrderList, in the following registry key

    HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

  3. The dependencies listed for each service.

When the boot is complete, the system executes the boot verification program specified by BootVerificationProgram value of the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

By default, this value is not set. The system simply reports that the boot was successful after the first user has logged on. You can supply a boot verification program that checks the system for problems and reports the boot status to the SCM using the NotifyBootConfigStatus function.

After a successful boot, the system saves a clone of the database in the last-known-good (LKG) configuration. The system can restore this copy of the database if changes made to the active database cause the system reboot to fail. The following is the registry key for this database,

HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Services

where XXX is the value saved in the following registry key value: HKEY_LOCAL_MACHINE\System\Select\LastKnownGood.

If an auto-start service with a SERVICE_ERROR_CRITICAL error control level fails to start, the SCM reboots the machine using the LKG configuration. If the LKG configuration is already being used, the boot fails.


Starting Services on Demand

The user can start a service with the Services control panel applet. A service control program can start a service with the StartService function. When the service is started, the SCM performs the following steps:

  • Retrieve the account information stored in the database.
  • Log on the service account.
  • Create the service in the suspended state.
  • Assign the logon token to the process.
  • Allow the process to execute.


Service Record List

As each service entry is read from the database of installed services, the SCM creates a service record for the service. A service record includes:

  • Service name
  • Start type (auto-start or demand-start)
  • Service status (see the SERVICE_STATUS structure)
    • Type
    • Current state
    • Acceptable control codes
    • Exit code
    • Wait hint
  • Pointer to dependency list

The user name and password of an account are specified at the time the service is installed. The SCM stores the user name in the registry and the password in a secure portion of the Local Security Authority (LSA). The system administrator can create accounts with passwords that never expire. Alternatively, the system administrator can create accounts with passwords that expire and manage the accounts by changing the passwords periodically.

The SCM updates the service status when a service sends it status notifications using the SetServiceStatus function. The SCM maintains the status of a driver service by querying the I/O system, instead of receiving status notifications, as it does from a service.

A service can register additional type information by calling the SetServiceBits function. The NetServerGetInfo and NetServerEnum functions obtain the supported service types.


SCM Handles

The SCM supports handle types to allow access to the following objects.

  • The database of installed services.
  • A service.
  • The database lock.

An SCManager object represents the database of installed services. It is a container object that holds service objects. The OpenSCManager function returns a handle to an SCManager object on a specified computer. This handle is used when installing, deleting, opening, and enumerating services and when locking the services database.

A service object represents an installed service. The CreateService and OpenService functions return handles to installed services.

The OpenSCManager, CreateService, and OpenService functions can request different types of access to SCManager and service objects. The requested access is granted or denied depending on the access token of the calling process and the security descriptor associated with the SCManager or service object.

The CloseServiceHandle function closes handles to SCManager and service objects. When you no longer need these handles, be sure to close them.

A lock object is created during SCM initialization to serialize access to the database of installed services. The SCM acquires the lock before starting a service or driver service. Service configuration programs use the LockServiceDatabase function to acquire the lock before reconfiguring a service and use the UnlockServiceDatabase function to release the lock.


Service Programs

A service program contains executable code for one or more services. A service created with the type SERVICE_WIN32_OWN_PROCESS only contains the code for one service. The service can be configured to execute in the context of a user account from either the built-in (local), primary, or trusted domain. A service created with the type SERVICE_WIN32_SHARE_PROCESS contains code for more than one service. For more information, see CreateService.

The following sections describe the interface requirements of the SCM that a service program must include. These sections do not apply to driver services.

  • The main Function
  • The ServiceMain Function
  • The Control Handler Function


The main Function

Service programs are generally written as console applications. The entry point of a console application is the main function. The main function receives arguments from the ImagePath value from the registry key for the service.

When the SCM starts a service program, it waits for it to call the StartServiceCtrlDispatcher function. Use the following guidelines.

  • A service of type SERVICE_WIN32_OWN_PROCESS should call StartServiceCtrlDispatcher immediately, from its main thread. You can perform any initialization after the service starts, as described in The ServiceMain Function.
  • If the service type is SERVICE_WIN32_SHARE_PROCESS and there is common initialization for all services in the program, you can perform the initialization in the main thread before calling StartServiceCtrlDispatcher, as long as it takes less than 30 seconds. Otherwise, you must create another thread to do the common initialization, while the main thread calls StartServiceCtrlDispatcher. You should still perform any service-specific initialization as described in The ServiceMain Function.

The StartServiceCtrlDispatcher function takes a SERVICE_TABLE_ENTRY structure for each service contained in the process. Each structure specifies the service name and the entry point for the service.

If StartServiceCtrlDispatcher succeeds, the calling thread does not return until all running services in the process have terminated. The SCM sends control requests to this thread through a named pipe. The thread acts as a control dispatcher, performing the following tasks:

  • Create a new thread to call the appropriate entry point when a new service is started.
  • Call the appropriate handler function to handle service control requests.

For more information, see Writing a Service Program's main Function.


The ServiceMain Function

The ServiceMain function is the entry point for a service.

When a service control program requests that a new service run, the SCM starts the service and sends a start request to the control dispatcher. The control dispatcher creates a new thread to execute the ServiceMain function for the service.

The ServiceMain function should perform the following tasks:

  1. Call the RegisterServiceCtrlHandlerEx function immediately to register a HandlerEx function to handle control requests for the service. The return value of RegisterServiceCtrlHandlerEx is a service status handle that will be used in calls to notify the SCM of the service status.
  2. Perform initialization. If the execution time of the initialization code is expected to be very short (less than one second), initialization can be performed directly in ServiceMain.

    If the initialization time is expected to be longer than one second, call the SetServiceStatus function, specifying the SERVICE_START_PENDING service state in the SERVICE_STATUS structure. As initialization continues, the service should make additional calls to SetServiceStatus to report progress. Sending multiple SetServiceStatus calls is useful for debugging services.

  3. When initialization is complete, call SetServiceStatus, specifying the SERVICE_RUNNING state in the SERVICE_STATUS structure.
  4. Perform the service tasks, or, if there are no pending tasks, return. Any change in the state of the service warrants a call to SetServiceStatus to report new status information.
  5. If an error occurs while the service is initializing or running, the service should call SetServiceStatus, specifying the SERVICE_STOP_PENDING state in the SERVICE_STATUS structure, if cleanup will be lengthy. Once cleanup is complete, call SetServiceStatus from the last thread to terminate, specifying SERVICE_STOPPED in the SERVICE_STATUS structure. Be sure to set the dwServiceSpecificExitCode and dwWin32ExitCode members of the SERVICE_STATUS structure to identify the error.

For more information, see Writing a ServiceMain Function.


The Control Handler Function

Each service has a control handler, the HandlerEx function, that is invoked by the control dispatcher when the service process receives a control request from a service control program. Therefore, this function executes in the context of the control dispatcher.

Whenever HandlerEx is invoked, the service must call the SetServiceStatus function to report its status to the SCM. This must be done regardless of whether the status changed.

The service control program can send control requests using the ControlService function. All services must accept and process the SERVICE_CONTROL_INTERROGATE control code. You can enable or disable acceptance of the other control codes by calling SetServiceStatus. To receive the SERVICE_CONTROL_DEVICEEVENT control code, you must call the RegisterDeviceNotification function. Services can also handle additional user-defined control codes.

The control handler must return within 30 seconds, or the SCM will return an error. If a service needs to do lengthy processing when the service is executing the control handler, it should create a secondary thread to perform the lengthy processing, then return. This prevents the service from tying up the control dispatcher. For example, when handling the stop request for a service that will take a long time, create another thread to handle the stop process. The control handler should simply call SetServiceStatus with the SERVICE_STOP_PENDING message and return.

When the user shuts down the system, all control handlers that have called SetServiceStatus with the SERVICE_ACCEPT_SHUTDOWN control code receive the SERVICE_CONTROL_SHUTDOWN control code. They are notified in the order that they appear in the database of installed services. By default, a service has approximately 20 seconds to perform cleanup tasks before the system shuts down. After this time expires, system shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not restarted or powered down), the service continues to run.

If the service needs more time to clean up, it sends STOP_PENDING status messages, along with a wait hint, so the service controller knows how long to wait before reporting to the system that service shutdown is complete. However, there is a limit to how long the service controller will wait, to prevent a service from stopping shutdown. To change this time limit, modify the WaitToKillServiceTimeout value in the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

For more information, see Writing a Control Handler Function.


Service Configuration Programs

Programmers and system administrators use service configuration programs to modify or query the database of installed services. The database can also be accessed by using the registry functions. However, you should only use the SCM configuration functions, which ensure that the service is properly installed and configured.

The SCM configuration functions require either a handle to an SCManager object or a handle to a service object. To obtain these handles, the service configuration program must:

  1. Use the OpenSCManager function to obtain a handle to the SCM database on a specified machine. For more information, see Opening an SCManager Database.
  2. Use the OpenService or CreateService function to obtain a handle to the service object.


Service Installation, Removal, and Enumeration

A configuration program uses the CreateService function to install a new service in the SCM database. This function specifies the name of the service and provides configuration information that is stored in the database. For a description of the information stored in the database for each service, see Database of Installed Services. For sample code, see Installing a Service.

A configuration program uses the DeleteService function to remove an installed service from the database. For more information, see Deleting a Service.

To obtain the service name, call the GetServiceKeyName function. The service display name, used in the Services control panel applet, can be obtained by calling the GetServiceDisplayName function.

A service configuration program can use the EnumServicesStatus function to enumerate all services and their statuses. It can also use the EnumDependentServices function to enumerate which services are dependent on a specified service object.


Service Configuration

The system uses the configuration information to determine how to start the service. The configuration information also includes the service display name and its description. For example, for the DHCP service, you could use the display name "Dynamic Host Configuration Protocol Service" and the description "Provides internet addresses for computer on your network."

To modify the configuration information for a service object, a configuration program uses the ChangeServiceConfig or ChangeServiceConfig2 function. For an example, see Changing a Service Configuration.

To retrieve the configuration information for a service object, the configuration program uses the QueryServiceConfig or QueryServiceConfig2 function. For an example, see Querying a Service's Configuration.

To modify the security descriptor for either an SCManager object or a service object, a configuration program uses the SetServiceObjectSecurity function. To retrieve a copy of the security descriptor, the configuration program uses the QueryServiceObjectSecurity function.

Before you reconfigure a service object, you should use the LockServiceDatabase function. This function tries to acquire a lock on the database and, if successful, prevents the SCM from starting a service while the database is being reconfigured. Failure to acquire a lock does not prevent a configuration program from successfully reconfiguring a service object. To release the lock on the database when the reconfiguration is complete, use the UnlockServiceDatabase function. To determine whether the database is locked, use the QueryServiceLockStatus function.


Configuring a Service Using SC

The Platform SDK contains a command-line utility, SC.EXE, that can be used to query or modify the database of installed services. Its commands correspond to the functions provided by the SCM. The syntax is:

sc ServerName [command] ServiceName

ServerName
Optional server name. Use the form \\ServerName.
Command
query
config
qc
delete
create
GetDisplayName
GetKeyName
EnumDepend
ServiceName
The name of the service, as specified when it was installed.


Service Control Programs

A service control program performs the following actions:

  • Starts a service or driver service, if the start type is SERVICE_DEMAND_START.
  • Sends control requests to a running service.
  • Queries the current status of a running service.

These actions require an open handle to the service object. To obtain the handle, the service control program must:

  1. Use the OpenSCManager function to obtain a handle to the SCM database on a specified machine.
  2. Use the OpenService or CreateService function to obtain a handle to the service object.


Service Startup

To start a service or driver service, the service control program uses the StartService function. The StartService function fails if the database is locked. If this occurs, the service control program should wait a few seconds and call StartService again. It can check the current lock status of the database by calling the QueryServiceLockStatus function.

If the service control program is starting a service, it can use the StartService function to specify an array of arguments to be passed to the service's ServiceMain function. The StartService function returns after a new thread has been created to execute the ServiceMain function. The service control program can retrieve the status of the newly started service in a SERVICE_STATUS structure by calling the QueryServiceStatus function. During initialization, the dwCurrentState member should be SERVICE_START_PENDING. The dwWaitHint member is a time interval, in milliseconds, that indicates how long the service control program should wait before calling QueryServiceStatus again. When the initialization is complete, the service changes dwCurrentState to SERVICE_RUNNING.

If the program is starting a driver service, StartService returns after the device driver has completed its initialization.

For more information, see Starting a Service.


Service Control Requests

To send control requests to a running service, a service control program uses the ControlService function. This function specifies a control value that is passed to the HandlerEx function of the specified service. This control value can be a user-defined code, or it can be one of the standard codes that enable the calling program to perform the following actions:

  • Stop a service (SERVICE_CONTROL_STOP).
  • Pause a service (SERVICE_CONTROL_PAUSE).
  • Resume executing a paused service (SERVICE_CONTROL_CONTINUE).
  • Retrieve updated status information from a service (SERVICE_CONTROL_INTERROGATE).

For more information, see Sending Control Requests to a Service.

Each service specifies the control values that it will accept and process. To determine which of the standard control values are accepted by a service, use the QueryServiceStatus function or specify the SERVICE_CONTROL_INTERROGATE control value in a call to the ControlService function. The dwControlsAccepted member of the SERVICE_STATUS structure returned by these functions indicates whether the service can be stopped, paused, or resumed. All services accept the SERVICE_CONTROL_INTERROGATE control value.

Note The QueryServiceStatus function reports the most recent status for a specified service, but does not get an updated status from the service itself. Using the SERVICE_CONTROL_INTERROGATE control value in a call to ControlService ensures that the status information returned is current.


Controlling a Service Using SC

The Platform SDK contains a command-line utility, SC.EXE, that can be used to control a service. Its commands correspond to the functions provided by the SCM. The syntax is:

sc ServerName [command] ServiceName

ServerName
Optional server name. Use the form \\ServerName.
Command
start
pause
interrogate
continue
stop
control
ServiceName
The name of the service, as specified when it was installed.


Service Security

When a process uses the OpenSCManager function to open a handle to a database of installed services, it can request different types of access. The system performs a security check before granting the requested access. All processes are permitted the following access to the database:

  • SC_MANAGER_CONNECT
  • SC_MANAGER_ENUMERATE_SERVICE
  • SC_MANAGER_QUERY_LOCK_STATUS

This enables any process to open a handle to the SCManager object that it can use in calls to the OpenService, EnumServicesStatus, and QueryServiceLockStatus functions. Only processes with Administrator privileges are able to open handles to the SCManager object that can be used by the CreateService and LockServiceDatabase functions.

When a process uses the OpenService function, the system performs an access check. The type of access permitted to different users depends on the SECURITY_DESCRIPTOR structure associated with the service object. The SCM creates a service object's security descriptor when the service is installed by the CreateService function. You can use the QueryServiceObjectSecurity and SetServiceObjectSecurity functions to query and set the security descriptor of a service object. The default security descriptor of a service object permits the following access:

  • Authenticated users have SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, SERVICE_ENUMERATE_DEPENDENTS, SERVICE_INTERROGATE, and SERVICE_USER_DEFINED_CONTROL access.
  • Members of the Power Users group and the LocalSystem account have SERVICE_START, SERVICE_PAUSE_CONTINUE, and SERVICE_STOP access, plus the access rights granted to all users.
  • Members of the Administrators and System Operators groups have SERVICE_ALL_ACCESS access.

Note that granting certain access to untrusted users (such as SERVICE_CHANGE_CONFIG or SERVICE_STOP) can allow them to interfere with the execution of your service, and possible allow them to run applications under the LocalSystem account.


Service User Accounts

Each service executes in the security context of a user account. The user name and password of an account are specified by the CreateService function at the time the service is installed. The user name and password can be changed by using the ChangeServiceConfig function. You can use the QueryServiceConfig function to get the user name (but not the password) associated with a service object.

When starting a service, the SCM logs on to the account associated with the service. If the log on is successful, the system produces an access token and attaches it to the new service process. This token identifies the service process in all subsequent interactions with securable objects (objects that have a security descriptor associated with them). For example, if the service tries to open a handle to a pipe, the system compares the service's access token to the pipe's security descriptor before granting access.

The SCM does not maintain the passwords of service user accounts. If a password is expired, the logon fails and the service fails to start. The system administrator who assigns accounts to services can create accounts with passwords that never expire. The administrator can also manage accounts with passwords that expire by using a service configuration program to periodically change the passwords.

If a service needs to recognize another service before sharing its information, the second service can either use the same account as the first service, or it can run in an account belonging to an alias that is recognized by the first service. Services that need to run in a distributed manner across the network should run in domain-wide accounts.


The LocalSystem Account

The LocalSystem account is a predefined local account used by system processes. The name of the account is .\System. This account does not have a password. If you specify the LocalSystem account in a call to the CreateService function, any password information you supply is ignored.

A service that runs in the context of the LocalSystem account inherits the security context of the SCM. It is not associated with any logged-on user account and does not have credentials (domain name, user name, and password) to be used for verification. This has several implications:

  • The registry key HKEY_CURRENT_USER is associated with the default user, not the current user. To access another user's profile, impersonate the user, then access HKEY_CURRENT_USER.
  • The service can open the registry key HKEY_LOCAL_MACHINE\SECURITY.
  • The service has limited access to network resources, such as shares and pipes, because it has no credentials and must connect using a null session. The following registry key contains the NullSessionPipes and NullSessionShares values, which are used to specify the pipes and shares to which null sessions may connect:

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\
    LanmanServer\Parameters

    Alternatively, you could add the REG_DWORD value RestrictNullSessAccess to the key and set it to 0 to allow all null sessions to access all pipes and shares created on that machine.

  • The service cannot share objects (pipes, file mapping, synchronization, and so on) with other applications, unless it creates them using either a DACL which allows a user or group of users access to the object or a NULL DACL, which allows everyone access to the object. Note that specifying a NULL DACL is not the same as specifying NULL. If you specify NULL in the lpSecurityDescriptor member of the SECURITY_ATTRIBUTES structure, access to the object is granted only to processes with the same security context as the process that created the object. For information on specifying a NULL DACL in the security descriptor field, see Allowing Access Using the Low-Level Functions.
  • If the service opens a command window and runs a batch file, the user could hit CTRL+C to terminate the batch file and gain access to a command window with LocalSystem permissions.


Interactive Services

An interactive service is a service that can interact with the input desktop. Other desktops do not receive user input. For more information, see Window Stations and Desktops.

An interactive service must run in the context of the LocalSystem account and be configured to run interactively. Services are configured to run interactively when the dwServiceType parameter in a CreateService call is set to include SERVICE_INTERACTIVE_PROCESS. However, the following registry key contains a value, NoInteractiveServices, that controls the effect of SERVICE_INTERACTIVE_PROCESS:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Windows

The NoInteractiveServices value defaults to zero, which means that services marked with SERVICE_INTERACTIVE_PROCESS will be allowed to run interactively. When the NoInteractiveServices value is set to a nonzero value, no service started thereafter, regardless of whether it has been configured with SERVICE_INTERACTIVE_PROCESS, will be allowed to run interactively.

Note It is possible to display a message box from a service, even if it is not running in the LocalSystem account or not configured to run interactively. Simply call the MessageBox function using MB_SERVICE_NOTIFICATION. Do not call MessageBox during service initialization or from the HandlerEx routine, unless you call it from a separate thread, so that you return to the SCM in a timely manner.

It is also possible to interact with the desktop from a non-interactive service by modifying the DACLs on the interface window station and desktop or by impersonating the logged-on user and opening the interactive window station and desktop directly. For more information, see Interacting with the User in a Service.


Receiving Device Events in a Service

The system broadcasts device change events to all services. These events can be received by a service in a window procedure or in its service control handler. To specify which events your service should receive, use the RegisterDeviceNotification function.

When a service calls RegisterDeviceNotification, the service also specifies either a window handle or a service status handle. If a service specifies a window handle, the window procedure receives the notification events. If a service specifies its service status handle, its service control handler receives the notification events. For more information, see HandlerEx.

Device notification handles returned by RegisterDeviceNotification must be closed by calling the UnregisterDeviceNotification function when they are no longer needed.


Debugging a Service

You can use the following methods to debug your service.

  • Use your debugger to debug the service while it is running. First, obtain the process identifier (PID) of the service process. This information is available from the PView application. After you have obtained the PID, attach to the running process. For syntax information, see the documentation included with your debugger.
  • Call the DebugBreak function to invoke the debugger for just-in-time debugging.
  • Specify a debugger to use when starting a program. To do so, create a key called Image File Execution Options in the following registry location:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion

    Create a subkey with the same name as your service (for example, MYSERV.EXE). To this subkey, add a value of type REG_SZ, named Debugger. Use the full path to the debugger as the string value. In the Services control panel applet, select your service, click Startup and check Allow Service to Interact with Desktop.

Note To debug the initialization code of an auto-start service, you will have to temporarily install and run the service as a demand-start service.


Using Services

  • Writing a service program's main function
  • Writing a ServiceMain function
  • Writing a control handler function
  • Opening an SCManager database
  • Installing a service
  • Deleting a service
  • Changing a service configuration
  • Querying a service's configuration
  • Starting a service
  • Sending control requests to a service


Writing a Service Program's main Function

The main function of a service program calls the StartServiceCtrlDispatcher function to connect to the SCM and start the control dispatcher thread. The dispatcher thread loops, waiting for incoming control requests for the services specified in the dispatch table. This thread does not return until there is an error or all of the services in the process have terminated. When all services in a process have terminated, the SCM sends a control request to the dispatcher thread telling it to shut down. The thread can then return from the StartServiceCtrlDispatcher call and the process can terminate.

The following example is a service process that supports only one service. It takes two parameters: a string that can contain one formatted output character and a numeric value to be used as the formatted character. The SvcDebugOut function prints informational messages and errors to the debugger. For information on writing the MyServiceStart and MyServiceInitialization functions, see Writing a ServiceMain Function. For information on writing the MyServiceCtrlHandler function, see Writing a Control Handler Function.

SERVICE_STATUS          MyServiceStatus;
SERVICE_STATUS_HANDLE   MyServiceStatusHandle;

VOID  MyServiceStart (DWORD argc, LPTSTR *argv);
VOID  MyServiceCtrlHandler (DWORD opcode);
DWORD MyServiceInitialization (DWORD argc, LPTSTR *argv,
        DWORD *specificError);

void main( )
{
    SERVICE_TABLE_ENTRY   DispatchTable[] =
    {
        { "MyService", MyServiceStart      },
        { NULL,              NULL          }
    };

    if (!StartServiceCtrlDispatcher( DispatchTable))
    {
        SvcDebugOut(" [MY_SERVICE] StartServiceCtrlDispatcher error =
            %d\n", GetLastError());
    }
}

VOID SvcDebugOut(LPSTR String, DWORD Status)
{
    CHAR  Buffer[1024];
    if (strlen(String) < 1000)
    {
        sprintf(Buffer, String, Status);
        OutputDebugStringA(Buffer);
    }
}

If your service program supports multiple services, the implementation of the main function will differ slightly. The names of the additional services should be added to the dispatch table so they can be monitored by the dispatcher thread.


Writing a ServiceMain Function

The MyServiceStart function in the following example is the entry point for the service. MyServiceStart has access to the command-line arguments, in the way that the main function of a console application does. The first parameter contains the number of arguments being passed to the service. There will always be at least one argument. The second parameter is a pointer to an array of string pointers. The first item in the array always points to the service name.

The MyServiceStart function first fills in the SERVICE_STATUS structure including the control codes that it accepts. Although this service accepts SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE, it does nothing significant when told to pause. SERVICE_ACCEPT_PAUSE_CONTINUE was included for illustration purposes only; if pausing does not add value to your service, do not support it.

The MyServiceStart function then calls the RegisterServiceCtrlHandler function to register MyService as the service's Handler function and begin initialization. The following sample initialization function, MyServiceInitialization, is included for illustration purposes; it does not perform any initialization tasks such as creating additional threads. If your service's initialization performs tasks that are expected to take longer than one second, your code must call the SetServiceStatus function periodically to send out wait hints and check points indicating that progress is being made.

When initialization has completed successfully, the example calls SetServiceStatus with a status of SERVICE_RUNNING and the service continues with its work. If an error has occurred in initialization, MyServiceStart reports SERVICE_STOPPED with the SetServiceStatus function and returns.

Because this sample service does not complete any real tasks, MyServiceStart simply returns control to the caller. However, your service should use this thread to complete whatever tasks it was designed to do. If a service does not need a thread to do its work (such as a service that only processes RPC requests), its ServiceMain function should return control to the caller. It is important for the function to return, rather than call the ExitThread function, because returning allows for cleanup of the memory allocated for the arguments.

To output debugging information, MyServiceStart calls SvcDebugOut. The source code for SvcDebugOut is given in Writing a Service Program's main Function.

SERVICE_STATUS          MyServiceStatus;
SERVICE_STATUS_HANDLE   MyServiceStatusHandle;

void MyServiceStart (DWORD argc, LPTSTR *argv)
{
    DWORD status;
    DWORD specificError;

    MyServiceStatus.dwServiceType        = SERVICE_WIN32;
    MyServiceStatus.dwCurrentState       = SERVICE_START_PENDING;
    MyServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP |
        SERVICE_ACCEPT_PAUSE_CONTINUE;
    MyServiceStatus.dwWin32ExitCode      = 0;
    MyServiceStatus.dwServiceSpecificExitCode = 0;
    MyServiceStatus.dwCheckPoint         = 0;
    MyServiceStatus.dwWaitHint           = 0;

    MyServiceStatusHandle = RegisterServiceCtrlHandler(
        "MyService",
        MyServiceCtrlHandler);

    if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0)
    {
        SvcDebugOut(" [MY_SERVICE] RegisterServiceCtrlHandler
            failed %d\n", GetLastError());
        return;
    }

    // Initialization code goes here.
    status = MyServiceInitialization(argc,argv, &specificError);

    // Handle error condition
    if (status != NO_ERROR)
    {
        MyServiceStatus.dwCurrentState       = SERVICE_STOPPED;
        MyServiceStatus.dwCheckPoint         = 0;
        MyServiceStatus.dwWaitHint           = 0;
        MyServiceStatus.dwWin32ExitCode      = status;
        MyServiceStatus.dwServiceSpecificExitCode = specificError;

        SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus);
        return;
    }

    // Initialization complete - report running status.
    MyServiceStatus.dwCurrentState       = SERVICE_RUNNING;
    MyServiceStatus.dwCheckPoint         = 0;
    MyServiceStatus.dwWaitHint           = 0;

    if (!SetServiceStatus (MyServiceStatusHandle, &MyServiceStatus))
    {
        status = GetLastError();
        SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
            %ld\n",status);
    }

    // This is where the service does its work.
    SvcDebugOut(" [MY_SERVICE] Returning the Main Thread \n",0);

    return;
}

// Stub initialization function.
DWORD MyServiceInitialization(DWORD   argc, LPTSTR  *argv,
    DWORD *specificError)
{
    argv;
    argc;
    specificError;
    return(0);
}


Writing a Control Handler Function

The MyServiceCtrlHandler function in the following example is the Handler function. When this function is called by the dispatcher thread, it handles the control code passed in the Opcode parameter and then calls the SetServiceStatus function to update the service's status. Every time a Handler function receives a control code, it is appropriate to return status with a call to SetServiceStatus regardless of whether the service acts on the control.

When the pause control is received, MyServiceCtrlHandler simply sets the dwCurrentState field in the SERVICE_STATUS structure to SERVICE_PAUSED. Likewise, when the continue control is received, the state is set to SERVICE_RUNNING. Therefore, MyServiceCtrlHandler is not a good example of how to handle the pause and continue controls. Because MyServiceCtrlHandler is a template for a Handler function, code for the pause and continue controls is included for completeness. A service that supports either the pause or continue control should handle these controls in a way that makes sense. Many services support neither the pause or continue control. If the service indicates that it does not support pause or continue with the dwControlsAccepted parameter, then the SCM will not send pause or continue controls to the service's Handler function.

To output debugging information, MyServiceCtrlHandler calls SvcDebugOut. The source code for SvcDebugOut is listed in Writing a Service Program's main Function. Also, note that the MyServiceStatus variable is a global variable and should be initialized as demonstrated in Writing a ServiceMain function.

SERVICE_STATUS          MyServiceStatus;
SERVICE_STATUS_HANDLE   MyServiceStatusHandle;

VOID MyServiceCtrlHandler (DWORD Opcode)
{
    DWORD status;

    switch(Opcode)
    {
        case SERVICE_CONTROL_PAUSE:
        // Do whatever it takes to pause here.
            MyServiceStatus.dwCurrentState = SERVICE_PAUSED;
            break;

        case SERVICE_CONTROL_CONTINUE:
        // Do whatever it takes to continue here.
            MyServiceStatus.dwCurrentState = SERVICE_RUNNING;
            break;

        case SERVICE_CONTROL_STOP:
        // Do whatever it takes to stop here.
            MyServiceStatus.dwWin32ExitCode = 0;
            MyServiceStatus.dwCurrentState  = SERVICE_STOPPED;
            MyServiceStatus.dwCheckPoint    = 0;
            MyServiceStatus.dwWaitHint      = 0;

            if (!SetServiceStatus (MyServiceStatusHandle,
                &MyServiceStatus))
            {
                status = GetLastError();
                SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
                    %ld\n",status);
            }

            SvcDebugOut(" [MY_SERVICE] Leaving MyService \n",0);
            return;

        case SERVICE_CONTROL_INTERROGATE:
        // Fall through to send current status.
            break;

        default:
            SvcDebugOut(" [MY_SERVICE] Unrecognized opcode %ld\n",
                Opcode);
    }

    // Send current status.
    if (!SetServiceStatus (MyServiceStatusHandle,  &MyServiceStatus))
    {
        status = GetLastError();
        SvcDebugOut(" [MY_SERVICE] SetServiceStatus error
            %ld\n",status);
    }
    return;
}


Opening an SCManager Database

Many operations require an open handle to an SCManager object. The following example demonstrates how to obtain the handle.

Different operations on the SCM database require different levels of access, and you should only request the minimum access required. If SC_MANAGER_ALL_ACCESS is requested, the OpenSCManager function fails if the calling process does not have administrator privileges. The following example shows how to request full access to the ServicesActive database on the local machine.

// Open a handle to the SC Manager database.

schSCManager = OpenSCManager(
    NULL,                    // local machine
    NULL,                    // ServicesActive database
    SC_MANAGER_ALL_ACCESS);  // full access rights

if (schSCManager == NULL)
    MyErrorExit("OpenSCManager");


Installing a Service

A service configuration program uses the CreateService function to install a service in a SCM database. The application-defined schSCManager handle must have SC_MANAGER_CREATE_SERVICE access to the SCManager object. The following example shows how to install a service.

VOID CreateSampleService()
{
    LPCTSTR lpszBinaryPathName =
        "%SystemRoot%\\system\\testserv.exe";

    schService = CreateService(
        schSCManager,              // SCManager database
        "Sample_Srv",              // name of service
        lpszDisplayName,           // service name to display
        SERVICE_ALL_ACCESS,        // desired access
        SERVICE_WIN32_OWN_PROCESS, // service type
        SERVICE_DEMAND_START,      // start type
        SERVICE_ERROR_NORMAL,      // error control type
        lpszBinaryPathName,        // service's binary
        NULL,                      // no load ordering group
        NULL,                      // no tag identifier
        NULL,                      // no dependencies
        NULL,                      // LocalSystem account
        NULL);                     // no password

    if (schService == NULL)
        MyErrorExit("CreateService");
    else
        printf("CreateService SUCCESS.\n");

    CloseServiceHandle(schService);
}


Deleting a Service

In the following example, a service configuration program uses the OpenService function to get a handle with DELETE access to an installed service object. The program then uses the service object handle in the DeleteService function to remove the service from the SCM database.

VOID DeleteSampleService()
{
    schService = OpenService(
        schSCManager,       // SCManager database
        "Sample_Srv",       // name of service
        DELETE);            // only need DELETE access

    if (schService == NULL)
        MyErrorExit("OpenService");

    if (! DeleteService(schService) )
        MyErrorExit("DeleteService");
    else
        printf("DeleteService SUCCESS\n");

    CloseServiceHandle(schService);
}


Changing a Service Configuration

In the following example, a service configuration program uses the ChangeServiceConfig and ChangeServiceConfig2 functions to change the configuration parameters of an installed service. The program first tries to lock the database, to prevent the SCM from starting a service while it is being reconfigured. If it successfully locks the database, the program opens a handle to the service object, modifies its configuration, unlocks the database, and then closes the service object handle. If the program does not successfully in lock the database, it uses the QueryServiceLockStatus function to retrieve information about the lock.

VOID ReconfigureSampleService(BOOL fDisable, LPSTR lpDesc)
{
    SC_LOCK sclLock;
    LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
    SERVICE_DESCRIPTION sdBuf;
    DWORD dwBytesNeeded, dwStartType;

    // Need to acquire database lock before reconfiguring.

    sclLock = LockServiceDatabase(schSCManager);

    // If the database cannot be locked, report the details.

    if (sclLock == NULL)
    {
        // Exit if the database is not locked by another process.

        if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED)
            MyErrorExit("LockServiceDatabase");

        // Allocate a buffer to get details about the lock.

        lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc(
            LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
        if (lpqslsBuf == NULL)
            MyErrorExit("LocalAlloc");

        // Get and print the lock status information.

        if (!QueryServiceLockStatus(
            schSCManager,
            lpqslsBuf,
            sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
            &dwBytesNeeded) )
            MyErrorExit("QueryServiceLockStatus");

        if (lpqslsBuf->fIsLocked)
            printf("Locked by: %s, duration: %d seconds\n",
                lpqslsBuf->lpLockOwner,
                lpqslsBuf->dwLockDuration);
        else
            printf("No longer locked\n");

        LocalFree(lpqslsBuf);
        MyErrorExit("Could not lock database");
    }

    // The database is locked, so it is safe to make changes.

    // Open a handle to the service.

    schService = OpenService(
        schSCManager,           // SCManager database
        "Sample_Srv",           // name of service
        SERVICE_CHANGE_CONFIG); // need CHANGE access
    if (schService == NULL)
        MyErrorExit("OpenService");

    dwStartType = (fDisable) ? SERVICE_DISABLED :
                            SERVICE_DEMAND_START;

    // Make the changes.

    if (! ChangeServiceConfig(
        schService,        // handle of service
        SERVICE_NO_CHANGE, // service type: no change
        dwStartType,       // change service start type
        SERVICE_NO_CHANGE, // error control: no change
        NULL,              // binary path: no change
        NULL,              // load order group: no change
        NULL,              // tag ID: no change
        NULL,              // dependencies: no change
        NULL,              // account name: no change
        NULL,              // password: no change
        NULL) )            // display name: no change
    {
        MyErrorExit("ChangeServiceConfig");
    }
    else
        printf("ChangeServiceConfig SUCCESS\n");

    sdBuf.lpDescription = lpDesc;

    if( !ChangeServiceConfig2(
        schService,                // handle to service
        SERVICE_CONFIG_DESCRIPTION // change: description
        &sdBuf) )                  // value: new description
    {
        MyErrorExit("ChangeServiceConfig2");
    }
    else
        printf("ChangeServiceConfig2 SUCCESS\n");

    // Release the database lock.

    UnlockServiceDatabase(sclLock);

    // Close the handle to the service.

    CloseServiceHandle(schService);
}


Querying a Service's Configuration

In the following example, a service configuration program uses the OpenService function to get a handle with SERVICE_QUERY_CONFIG access to an installed service object. Then the program uses the service object handle in the QueryServiceConfig function to retrieve the current configuration of the service.

VOID GetSampleServiceConfig()
{
    LPQUERY_SERVICE_CONFIG lpqscBuf;
    LPSERVICE_DESCRIPTION lpqscBuf2;
    DWORD dwBytesNeeded;

    // Open a handle to the service.

    schService = OpenService(
        schSCManager,           // SCManager database
        "Sample_Srv",           // name of service
        SERVICE_QUERY_CONFIG);  // need QUERY access
    if (schService == NULL)
        MyErrorExit("OpenService");

    // Allocate a buffer for the configuration information.

    lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc(
        LPTR, 4096);
    if (lpqscBuf == NULL)
        MyErrorExit("LocalAlloc");

    lpqscBuf2 = (LPSERVICE_DESCRIPTION) LocalAlloc(
        LPTR, 4096);
    if (lpqscBuf2 == NULL)
        MyErrorExit("LocalAlloc");

    // Get the configuration information.

    if (! QueryServiceConfig(
        schService,
        lpqscBuf,
        4096,
        &dwBytesNeeded) )
    {
        MyErrorExit("QueryServiceConfig");
    }

    if (! QueryServiceConfig2(
        schService,
        SERVICE_CONFIG_DESCRIPTION,
        lpqscBuf2,
        4096,
        &dwBytesNeeded) )
    {
        MyErrorExit("QueryServiceConfig2");
    }

    // Print the configuration information.

    printf("\nSample_Srv configuration: \n");
    printf(" Type: 0x%x\n", lpqscBuf->dwServiceType);
    printf(" Start Type: 0x%x\n", lpqscBuf->dwStartType);
    printf(" Error Control: 0x%x\n", lpqscBuf->dwErrorControl);
    printf(" Binary path: %s\n", lpqscBuf->lpBinaryPathName);

    if (lpqscBuf->lpLoadOrderGroup != NULL)
        printf(" Load order group: %s\n", lpqscBuf->lpLoadOrderGroup);
    if (lpqscBuf->dwTagId != 0)
        printf(" Tag ID: %d\n", lpqscBuf->dwTagId);
    if (lpqscBuf->lpDependencies != NULL)
        printf(" Dependencies: %s\n", lpqscBuf->lpDependencies);
    if (lpqscBuf->lpServiceStartName != NULL)
        printf(" Start Name: %s\n", lpqscBuf->lpServiceStartName);
    if (lpqscBuf2->lpDescription != NULL)
        printf(" Description: %s\n", lpqscBuf2->lpDescription);

    LocalFree(lpqscBuf);
    LocalFree(lpqscBuf2);
}


Starting a Service

To start a service, the following example opens a handle to an installed database and then specifies the handle in a call to the StartService function. It can be used to start either a service or a driver service, but this example assumes that a service is being started. After starting the service, the program uses the members of the SERVICE_STATUS structure returned by the QueryServiceStatus function to track the progress of the service.

DWORD StartSampleService()
{
    SERVICE_STATUS ssStatus;
    DWORD dwOldCheckPoint;
    DWORD dwStartTickCount;
    DWORD dwWaitTime;
    DWORD dwStatus;

    schService = OpenService(
        schSCManager,          // SCM database
        "Sample_Srv",          // service name
        SERVICE_ALL_ACCESS);

    if (schService == NULL)
    {
        MyErrorExit("OpenService");
    }

    if (!StartService(
            schService,  // handle to service
            0,           // number of arguments
            NULL) )      // no arguments
    {
        MyErrorExit("StartService");
    }
    else
    {
        printf("Service start pending.\n");
    }

    // Check the status until the service is no longer start pending.

    if (!QueryServiceStatus(
            schService,   // handle to service
            &ssStatus) )  // address of status information structure
    {
        MyErrorExit("QueryServiceStatus");
    }

    // Save the tick count and initial checkpoint.

    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = ssStatus.dwCheckPoint;

    while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
    {
        // Do not wait longer than the wait hint. A good interval is
        // one tenth the wait hint, but no less than 1 second and no
        // more than 10 seconds.

        dwWaitTime = ssStatus.dwWaitHint / 10;

        if( dwWaitTime < 1000 )
            dwWaitTime = 1000;
        else if ( dwWaitTime > 10000 )
            dwWaitTime = 10000;

        Sleep( dwWaitTime );

        // Check the status again.

        if (!QueryServiceStatus(
                schService,   // handle to service
                &ssStatus) )  // address of structure
            break;

        if ( ssStatus.dwCheckPoint > dwOldCheckPoint )
        {
            // The service is making progress.

            dwStartTickCount = GetTickCount():
            dwOldCheckPoint = ssStatus.dwCheckPoint;
        }
        else
        {
            if(GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
            {
                // No progress made within the wait hint
                break;
            }
        }
    }

    if (ssStatus.dwCurrentState == SERVICE_RUNNING)
    {
        printf("StartService SUCCESS.\n");
        dwStatus = NO_ERROR;
    }
    else
    {
        printf("\nService not started. \n");
        printf("  Current State: %d\n", ssStatus.dwCurrentState);
        printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode);
        printf("  Service Specific Exit Code: %d\n",
            ssStatus.dwServiceSpecificExitCode);
        printf("  Check Point: %d\n", ssStatus.dwCheckPoint);
        printf("  Wait Hint: %d\n", ssStatus.dwWaitHint);
        dwStatus = GetLastError();
    }

    CloseServiceHandle(schService);
    return dwStatus;
}


Sending Control Requests to a Service

The following example uses the ControlService function to send a control value to a running service. Different control values require different levels of access to the service object. For example, a service object handle must have SERVICE_STOP access to send the SERVICE_CONTROL_STOP control code. When ControlService returns, a SERVICE_STATUS structure contains the latest status information for the service.

VOID ControlSampleService(DWORD fdwControl)
{
    SERVICE_STATUS ssStatus;
    DWORD fdwAccess;
    DWORD dwStartTickCount, dwWaitTime;

    // The required service object access depends on the control.

    switch (fdwControl)
    {
        case SERVICE_CONTROL_STOP:
            fdwAccess = SERVICE_STOP;
            break;

        case SERVICE_CONTROL_PAUSE:
        case SERVICE_CONTROL_CONTINUE:
            fdwAccess = SERVICE_PAUSE_CONTINUE;
            break;

        case SERVICE_CONTROL_INTERROGATE:
            fdwAccess = SERVICE_INTERROGATE;
            break;

        default:
            fdwAccess = SERVICE_INTERROGATE;
    }

    // Open a handle to the service.

    schService = OpenService(
        schSCManager,        // SCManager database
        "Sample_Srv",        // name of service
        fdwAccess);          // specify access
    if (schService == NULL)
        MyErrorExit("OpenService");

    // Send a control value to the service.

    if (! ControlService(
            schService,   // handle to service
            fdwControl,   // control value to send
            &ssStatus) )  // address of status info
    {
        MyErrorExit("ControlService");
    }

    // Print the service status.

    printf("\nStatus of Sample_Srv: \n");
    printf("  Service Type: 0x%x\n", ssStatus.dwServiceType);
    printf("  Current State: 0x%x\n", ssStatus.dwCurrentState);
    printf("  Controls Accepted: 0x%x\n",
        ssStatus.dwControlsAccepted);
    printf("  Exit Code: %d\n", ssStatus.dwWin32ExitCode);
    printf("  Service Specific Exit Code: %d\n",
        ssStatus.dwServiceSpecificExitCode);
    printf("  Check Point: %d\n", ssStatus.dwCheckPoint);
    printf("  Wait Hint: %d\n", ssStatus.dwWaitHint);

    return;
}


Service Reference

The following elements are used with services.

  • Service Functions
  • Service Structures


Service Functions

The following functions are used by services and by programs that control or configure services.

Function | Description
ChangeServiceConfig | Changes the configuration parameters of a service.
ChangeServiceConfig2 | Changes the optional configuration parameters of a service.
CloseServiceHandle | Closes the specified handle to a service control manager object or a service object.
ControlService | Sends a control code to a service.
CreateService | Creates a service object and adds it to the specified service control manager database.
DeleteService | Marks the specified service for deletion from the service control manager database.
EnumDependentServices | Retrieves the name and status of each service that depends on the specified service.
EnumServicesStatus | Enumerates services in the specified service control manager database.
EnumServicesStatusEx | Enumerates services in the specified service control manager database based on the specified information level.
GetServiceDisplayName | Retrieves the display name of the specified service.
GetServiceKeyName | Retrieves the service name of the specified service.
Handler | An application-defined callback function used with the RegisterServiceCtrlHandler function.
HandlerEx | An application-defined callback function used with the RegisterServiceCtrlHandlerEx function.
LockServiceDatabase | Requests ownership of the service control manager database lock.
NotifyBootConfigStatus | Reports the boot status to the service control manager.
OpenSCManager | Establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.
OpenService | Opens an existing service.
QueryServiceConfig | Retrieves the configuration parameters of the specified service.
QueryServiceConfig2 | Retrieves the optional configuration parameters of the specified service.
QueryServiceLockStatus | Retrieves the lock status of the specified service control manager database.
QueryServiceObjectSecurity | Retrieves a copy of the security descriptor associated with a service object.
QueryServiceStatus | Retrieves the current status of the specified service.
QueryServiceStatusEx | Retrieves the current status of the specified service based on the specified information level.
RegisterServiceCtrlHandler | Register a function to handle service control requests for an application.
RegisterServiceCtrlHandlerEx | Register a function to handle service control requests for an application.
ServiceMain | An application-defined function that serves as the entry point for a service.
SetServiceBits | Registers a service type with the service control manager and the Server service.
SetServiceObjectSecurity | Sets the security descriptor of a service object.
SetServiceStatus | Updates the service control manager's status information for the calling service.
StartService | Starts a service.
StartServiceCtrlDispatcher | Connects the main thread of a service process to the service control manager.
UnlockServiceDatabase | Unlocks a service control manager database by releasing the specified lock.


ChangeServiceConfig

The ChangeServiceConfig function changes the configuration parameters of a service.

To change the optional configuration parameters, use the ChangeServiceConfig2 function.

BOOL ChangeServiceConfig(
  SC_HANDLE hService          // handle to service
  DWORD dwServiceType,        // type of service
  DWORD dwStartType,          // when to start service
  DWORD dwErrorControl,       // severity of start failure
  LPCTSTR lpBinaryPathName,   // service binary file name
  LPCTSTR lpLoadOrderGroup,   // load ordering group name
  LPDWORD lpdwTagId,          // tag identifier
  LPCTSTR lpDependencies,     // array of dependency names
  LPCTSTR lpServiceStartName, // account name
  LPCTSTR lpPassword,         // account password
  LPCTSTR lpDisplayName       // display name
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function and must have SERVICE_CHANGE_CONFIG access.
dwServiceType
[in] Specifies the type of service. Specify SERVICE_NO_CHANGE if you are not changing the existing service type; otherwise, specify one of the following service types.
Type | Meaning
SERVICE_FILE_SYSTEM_DRIVER | Specifies a file system driver service.
SERVICE_KERNEL_DRIVER | Specifies a driver service.
SERVICE_WIN32_OWN_PROCESS | Specifies a service that runs in its own process.
SERVICE_WIN32_SHARE_PROCESS | Specifies a service that shares a process with other services.

If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, you can also specify the following type.
Type | Meaning
SERVICE_INTERACTIVE_PROCESS | Enables a service to interact with the desktop.

dwStartType
[in] Specifies when to start the service. Specify SERVICE_NO_CHANGE if you are not changing the existing start type; otherwise, specify one of the following start types.
Type | Meaning
SERVICE_AUTO_START | Specifies a service to be started automatically by the service control manager during system startup.
SERVICE_BOOT_START | Specifies a device driver started by the system loader. This value is valid only for driver services.
SERVICE_DEMAND_START | Specifies a service to be started by the service control manager when a process calls the StartService function.
SERVICE_DISABLED | Specifies a service that can no longer be started.
SERVICE_SYSTEM_START | Specifies a device driver started by the IoInitSystem function. This value is valid only for driver services.

dwErrorControl
[in] Specifies the severity of the error if this service fails to start during startup, and determines the action taken by the startup program if failure occurs. Specify SERVICE_NO_CHANGE if you are not changing the existing error control; otherwise, specify one of the following values to indicate the error control.
Values | Meaning
SERVICE_ERROR_IGNORE | The startup program logs the error but continues the startup operation.
SERVICE_ERROR_NORMAL | The startup program logs the error and puts up a message box pop-up but continues the startup operation.
SERVICE_ERROR_SEVERE | The startup program logs the error. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
SERVICE_ERROR_CRITICAL | The startup program logs the error, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.

lpBinaryPathName
[in] Pointer to a null-terminated string that contains the fully qualified path to the service binary file. Specify NULL if you are not changing the existing path. If the path contains a space, it must be quoted so that it is correctly interpreted. For example, "d:\\my share\\myservice.exe" should be specified as "\"d:\\my share\\myservice.exe\"".
lpLoadOrderGroup
[in] Pointer to a null-terminated string that names the load ordering group of which this service is a member. Specify NULL if you are not changing the existing group. Specify an empty string if the service does not belong to a group.
lpdwTagId
[out] Pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter. Specify NULL if you are not changing the existing tag.

You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the GroupOrderList value of the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

Tags are only evaluated for driver services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies
[in] Pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must start before this service can be started. (Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.) Specify NULL if you are not changing the existing dependencies. Specify an empty string if the service has no dependencies.

You must prefix group names with SC_GROUP_IDENTIFIER so that they can be distinguished from a service name, because services and service groups share the same name space.

lpServiceStartName
[in] Pointer to a null-terminated string that specifies the service name. Specify NULL if you are not changing the existing name. If the service type is SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName. The service process will be logged on as this user. If the account belongs to the built-in domain, you can specify .\UserName.

Windows NT 4.0 and earlier: If the service type is SERVICE_WIN32_SHARE_PROCESS, you must specify the LocalSystem account. On Windows 2000 and later, a shared process can run as any user.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, the name is the driver object name that the system uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.

For more information, see the warning in the Remarks section.

lpPassword
[in] Pointer to a null-terminated string that contains the password to the account name specified by the lpServiceStartName parameter. Specify an empty string if the account has no password. Specify NULL if the service runs in the LocalSystem account.

Passwords are ignored for driver services.

lpDisplayName
[in] Pointer to a null-terminated string that contains the display name to be used by applications to identify the service for its users. This string has a maximum length of 256 characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SERVICE_CHANGE_CONFIG access.
ERROR_CIRCULAR_DEPENDENCY | A circular service dependency was specified.
ERROR_DUP_NAME | The display name already exists in the service controller manager database, either as a service name or as another display name.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_INVALID_PARAMETER | A parameter that was specified is invalid.
ERROR_INVALID_SERVICE_ACCOUNT | The account name does not exist, or a service is specified to share the same binary file as an already installed service but with an account name that is not the same as the installed service.
ERROR_SERVICE_MARKED_FOR_DELETE | The service has been marked for deletion.

Remarks

The ChangeServiceConfig function changes the configuration information for the specified service in the service control manager database. You can obtain the current configuration information by using the QueryServiceConfig function.

If the configuration is changed for a service that is running, with the exception of lpDisplayName, the changes do not take effect until the service is stopped.

The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups in the list. The list of load ordering groups is contained in the ServiceGroupOrder value of the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

Warning Setting the lpServiceStartName parameter changes the logon account of the service. This can cause problems. If you have registered a service principal name (SPN), it would now be registered on the wrong account. Similarly, if you have used an ACE to grant access to a service, it would now grant access to the wrong account.

For example, see Changing a Service Configuration.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, ChangeServiceConfig2, CreateService, OpenService, QueryServiceConfig, QueryServiceConfig2, StartService


ChangeServiceConfig2

The ChangeServiceConfig2 function changes the optional configuration parameters of a service.

BOOL ChangeServiceConfig2(
  SC_HANDLE hService,  // handle to service
  DWORD dwInfoLevel,   // information level
  LPVOID lpInfo        // new data
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function and must have the SERVICE_CHANGE_CONFIG access right.

If one of the specified service controller actions is SC_ACTION_RESTART, hService must have the SERVICE_START access right.

dwInfoLevel
[in] Specifies the configuration information to change. This parameter can be one of the following values.
Value | Meaning
SERVICE_CONFIG_DESCRIPTION | The lpInfo parameter is a pointer to a SERVICE_DESCRIPTION structure.
SERVICE_CONFIG_FAILURE_ACTIONS | The lpInfo parameter is a pointer to a SERVICE_FAILURE_ACTIONS structure.

lpInfo
[in] Pointer to the new value to be set for the configuration information. The format of this data depends on the value of the dwInfoLevel parameter. If this value is NULL, the information remains unchanged.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The ChangeServiceConfig2 function changes the optional configuration information for the specified service in the service control manager database. You can obtain the current optional configuration information by using the QueryServiceConfig2 function.

You cannot set the SERVICE_CONFIG_FAILURE_ACTIONS value for a service that shares the service control manager's process. This includes all services whose executable image is "services.exe".

You can change and query additional configuration information using the ChangeServiceConfig and QueryServiceConfig functions, respectively.

For example, see Changing a Service Configuration.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows 2000.

See Also

Services Overview, Service Functions, ChangeServiceConfig, CreateService, OpenService, QueryServiceConfig, QueryServiceConfig2, SERVICE_DESCRIPTION, SERVICE_FAILURE_ACTIONS


CloseServiceHandle

The CloseServiceHandle function closes the following types of handles:

  • handle to a service control manager object as returned by the OpenSCManager function
  • handle to a service object as returned by either the OpenService or CreateService function
BOOL CloseServiceHandle(
  SC_HANDLE hSCObject   // handle to service or SCM object
);

Parameters

hSCObject
[in] Handle to the service control manager object or the service object to close.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error code can be set by the service control manager. Other error codes can be set by registry functions that are called by the service control manager.

Error code | Meaning
ERROR_INVALID_HANDLE | The specified handle is invalid.

Remarks

The CloseServiceHandle function does not destroy the service control manager object referred to by the handle. A service control manager object cannot be destroyed. A service object can be destroyed by calling the DeleteService function.

For example, see Deleting a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, CreateService, DeleteService, OpenSCManager, OpenService


ControlService

The ControlService function sends a control code to a service.

BOOL ControlService(
  SC_HANDLE hService,               // handle to service
  DWORD dwControl,                  // control code
  LPSERVICE_STATUS lpServiceStatus  // status information
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function. The access required for this handle depends on the dwControl code requested.
dwControl
[in] Specifies the requested control code. This value can be one of the following control codes.
Control code | Description
SERVICE_CONTROL_CONTINUE | Notifies a paused service that it should resume. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_INTERROGATE | Notifies a service that it should report its current status information to the service control manager. The hService handle must have SERVICE_INTERROGATE access.
SERVICE_CONTROL_NETBINDADD | Windows 2000 and later: Notifies a network service that there is a new component for binding. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_NETBINDDISABLE | Windows 2000 and later: Notifies a network service that one of its bindings has been disabled. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_NETBINDENABLE | Windows 2000 and later: Notifies a network service that a disabled binding has been enabled. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_NETBINDREMOVE | Windows 2000 and later: Notifies a network service that that a component for binding has been removed. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_PARAMCHANGE | Windows 2000 and later: Notifies a service that its startup parameters have changed. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_PAUSE | Notifies a service that it should pause. The hService handle must have SERVICE_PAUSE_CONTINUE access.
SERVICE_CONTROL_STOP | Notifies a service that it should stop. The hService handle must have SERVICE_STOP access.

This value can also be a user-defined control code, as described in the following table.
Control code | Meaning
Range 128 to 255. | The service defines the action associated with the control code. The hService handle must have SERVICE_USER_DEFINED_CONTROL access.

lpServiceStatus
[out] Pointer to a SERVICE_STATUS structure that receives the latest service status information. The information returned reflects the most recent status that the service reported to the service control manager.

The service control manager fills in the structure only when ControlService returns one of the following error codes: NO_ERROR, ERROR_INVALID_SERVICE_CONTROL, ERROR_SERVICE_CANNOT_ACCEPT_CTRL, or ERROR_SERVICE_NOT_ACTIVE. Otherwise, the structure is not filled in.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with the necessary access.
ERROR_DEPENDENT_SERVICES_RUNNING | The service cannot be stopped because other running services are dependent on it.
ERROR_INVALID_HANDLE | The specified handle was not obtained using CreateService or OpenService, or the handle is no longer valid.
ERROR_INVALID_PARAMETER | The requested control code is undefined.
ERROR_INVALID_SERVICE_CONTROL | The requested control code is not valid, or it is unacceptable to the service.
ERROR_SERVICE_CANNOT_ACCEPT_CTRL | The requested control code cannot be sent to the service because the state of the service is SERVICE_STOPPED, SERVICE_START_PENDING, or SERVICE_STOP_PENDING.
ERROR_SERVICE_NOT_ACTIVE | The service has not been started.
ERROR_SERVICE_REQUEST_TIMEOUT | The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called StartServiceCtrlDispatcher may be blocked in a control handler function.
ERROR_SHUTDOWN_IN_PROGRESS | The system is shutting down.

Remarks

The ControlService function asks the service control manager to send the requested control code to the service. The service control manager sends the code if the service accepts the control and if the service is in a state in which a control can be sent to it. You cannot stop and start a service unless the security descriptor allows you to. The default security descriptor allows the LocalSystem account, and members of the Administrators and Power Users groups to stop and start services. To change the security descriptor of a service, use SetServiceObjectSecurity.

The QueryServiceStatus or function returns a SERVICE_STATUS structure whose dwCurrentState and dwControlsAccepted members indicate the current state and controls accepted by a running service. All running services accept the SERVICE_CONTROL_INTERROGATE control code by default. Drivers do not accept control codes other than SERVICE_CONTROL_STOP and SERVICE_CONTROL_INTERROGATE. Each service specifies the other control codes that it accepts when it calls the SetServiceStatus function to report its status. A service should always accept these codes when it is running, no matter what it is doing.

The following table shows the action of the service control manager in each of the possible service states.

Service state | Stop | Other controls
STOPPED | (c) | (c)
STOP_PENDING | (b) | (b)
START_PENDING | (a) | (b)
RUNNING | (a) | (a)
CONTINUE_PENDING | (a) | (a)
PAUSE_PENDING | (a) | (a)
PAUSED | (a) | (a)
 | (a) | If the service accepts this control code, send the request to the service; otherwise, ControlService returns zero and GetLastError returns ERROR_INVALID_SERVICE_CONTROL.
 | (b) | The service is not in a state in which a control can be sent to it, so ControlService returns zero and GetLastError returns ERROR_SERVICE_CANNOT_ACCEPT_CTRL.
 | (c) | The service is not active, so ControlService returns zero and GetLastError returns ERROR_SERVICE_NOT_ACTIVE.

For example, see Sending Control Requests to a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, CreateService, OpenService, QueryServiceStatus, SetServiceObjectSecurity, SetServiceStatus, SERVICE_STATUS


CreateService

The CreateService function creates a service object and adds it to the specified service control manager database.

SC_HANDLE CreateService(
  SC_HANDLE hSCManager,       // handle to SCM database
  LPCTSTR lpServiceName,      // name of service to start
  LPCTSTR lpDisplayName,      // display name
  DWORD dwDesiredAccess,      // type of access to service
  DWORD dwServiceType,        // type of service
  DWORD dwStartType,          // when to start service
  DWORD dwErrorControl,       // severity of service failure
  LPCTSTR lpBinaryPathName,   // name of binary file
  LPCTSTR lpLoadOrderGroup,   // name of load ordering group
  LPDWORD lpdwTagId,          // tag identifier
  LPCTSTR lpDependencies,     // array of dependency names
  LPCTSTR lpServiceStartName, // account name
  LPCTSTR lpPassword          // account password
);

Parameters

hSCManager
[in] Handle to the service control manager database. This handle is returned by the OpenSCManager function and must have SC_MANAGER_CREATE_SERVICE access.
lpServiceName
[in] Pointer to a null-terminated string that specifies the name of the service to install. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and back-slash (\) are invalid service name characters.
lpDisplayName
[in] Pointer to a null-terminated string that contains the display name to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the service control manager. display name comparisons are always case-insensitive.
dwDesiredAccess
[in] Specifies the access to the service. Before granting the requested access, the system checks the access token of the calling process.

The STANDARD_RIGHTS_REQUIRED constant enables the following object access types.
Standard rights | Description
ACCESS_SYSTEM_SECURITY | Enables calling of the QueryServiceObjectSecurity or SetServiceObjectSecurity function to access the SACL. The proper way to obtain this access is to enable the SE_SECURITY_NAME privilege in the caller's current access token, open the handle for ACCESS_SYSTEM_SECURITY access, and then disable the privilege.
DELETE | Enables calling of the DeleteService function to delete the service.
READ_CONTROL | Enables calling of the QueryServiceObjectSecurity function to query the security descriptor of the service object.
WRITE_DAC | Enables calling of the SetServiceObjectSecurity function to modify the Dacl member of the service object's security descriptor.
WRITE_OWNER | Enables calling of the SetServiceObjectSecurity function to modify the Owner and Group members of the service object's security descriptor.

You can specify any or all of the following service object access types.
Object access | Description
SERVICE_ALL_ACCESS | Includes STANDARD_RIGHTS_REQUIRED in addition to all of the access types listed in this table.
SERVICE_CHANGE_CONFIG | Enables calling of the ChangeServiceConfig function to change the service configuration.
SERVICE_ENUMERATE_DEPENDENTS | Enables calling of the EnumDependentServices function to enumerate all the services dependent on the service.
SERVICE_INTERROGATE | Enables calling of the ControlService function to ask the service to report its status immediately.
SERVICE_PAUSE_CONTINUE | Enables calling of the ControlService function to pause or continue the service.
SERVICE_QUERY_CONFIG | Enables calling of the QueryServiceConfig function to query the service configuration.
SERVICE_QUERY_STATUS | Enables calling of the QueryServiceStatus function to ask the service control manager about the status of the service.
SERVICE_START | Enables calling of the StartService function to start the service.
SERVICE_STOP | Enables calling of the ControlService function to stop the service.
SERVICE_USER_DEFINED_CONTROL | Enables calling of the ControlService function to specify a user-defined control code.

You can specify any of the following generic access types.
Generic access | Service access
GENERIC_READ | Combines the following access types: STANDARD_RIGHTS_READ, SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, SERVICE_INTERROGATE, and SERVICE_ENUMERATE_DEPENDENTS.
GENERIC_WRITE | Combines the following access types: STANDARD_RIGHTS_WRITE and SERVICE_CHANGE_CONFIG.
GENERIC_EXECUTE | Combines the following access types: STANDARD_RIGHTS_EXECUTE, SERVICE_START, SERVICE_STOP, SERVICE_PAUSE_CONTINUE, and SERVICE_USER_DEFINED_CONTROL.

dwServiceType
[in] Specifies the type of service. This parameter must be one of the following service types.
Type | Meaning
SERVICE_FILE_SYSTEM_DRIVER | Specifies a file system driver service.
SERVICE_KERNEL_DRIVER | Specifies a driver service.
SERVICE_WIN32_OWN_PROCESS | Specifies a service that runs in its own process.
SERVICE_WIN32_SHARE_PROCESS | Specifies a service that shares a process with other services.

If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, you can also specify the following type.
Type Meaning
SERVICE_INTERACTIVE_PROCESS Enables a service to interact with the desktop.

This value is valid only if lpServiceStartName is the LocalSystem account. For more information, see Interactive Services.

dwStartType
[in] Specifies when to start the service. This parameter must be one of the following start types.
Type | Meaning
SERVICE_AUTO_START | Specifies a service to be started automatically by the service control manager during system startup.
SERVICE_BOOT_START | Specifies a device driver started by the system loader. This value is valid only for driver services.
SERVICE_DEMAND_START | Specifies a service to be started by the service control manager when a process calls the StartService function.
SERVICE_DISABLED | Specifies a service that can no longer be started.
SERVICE_SYSTEM_START | Specifies a device driver started by the IoInitSystem function. This value is valid only for driver services.

dwErrorControl
[in] Specifies the severity of the error if this service fails to start during startup, and determines the action taken by the startup program if failure occurs. This parameter must be one of the following values.
Value | Meaning
SERVICE_ERROR_IGNORE | The startup program logs the error but continues the startup operation.
SERVICE_ERROR_NORMAL | The startup program logs the error and puts up a message box pop-up but continues the startup operation.
SERVICE_ERROR_SEVERE | The startup program logs the error. If the last-known-good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
SERVICE_ERROR_CRITICAL | The startup program logs the error, if possible. If the last-known-good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.

lpBinaryPathName
[in] Pointer to a null-terminated string that contains the fully qualified path to the service binary file. If the path contains a space, it must be quoted so that it is correctly interpreted. For example, "d:\\my share\\myservice.exe" should be specified as "\"d:\\my share\\myservice.exe\"".
lpLoadOrderGroup
[in] Pointer to a null-terminated string that names the load ordering group of which this service is a member. Specify NULL or an empty string if the service does not belong to a group.
lpdwTagId
[out] Pointer to a variable that receives a tag value that is unique in the group specified in the lpLoadOrderGroup parameter. Specify NULL if you are not changing the existing tag.

You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the GroupOrderList value of the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control

Tags are only evaluated for driver services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies
[in] Pointer to a double null-terminated array of null-separated names of services or load ordering groups that the system must start before this service. Specify NULL or an empty string if the service has no dependencies. Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.

You must prefix group names with SC_GROUP_IDENTIFIER so that they can be distinguished from a service name, because services and service groups share the same name space.

lpServiceStartName
[in] Pointer to a null-terminated string that specifies the service name. If the service type is SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName. The service process will be logged on as this user. If the account belongs to the built-in domain, you can specify .\UserName.

If this parameter is NULL, CreateService uses the LocalSystem account.

Windows NT 4.0 and earlier: If the service type is SERVICE_WIN32_SHARE_PROCESS, you must specify the LocalSystem account. On Windows 2000 and later, a shared process can run as any user.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, the name is the driver object name that the system uses to load the device driver. Specify NULL if the driver is to use a default object name created by the I/O system.

If the service type specifies SERVICE_INTERACTIVE_PROCESS, the service must run in the LocalSystem account.

lpPassword
[in] Pointer to a null-terminated string that contains the password to the account name specified by the lpServiceStartName parameter. Specify an empty string if the account has no password. Specify NULL is the service runs in the LocalSystem account.

Passwords are ignored for driver services.

Return Values

If the function succeeds, the return value is a handle to the service.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The handle to the specified service control manager database does not have SC_MANAGER_CREATE_SERVICE access.
ERROR_CIRCULAR_DEPENDENCY | A circular service dependency was specified.
ERROR_DUP_NAME | The display name already exists in the service control manager database either as a service name or as another display name.
ERROR_INVALID_HANDLE | The handle to the specified service control manager database is invalid.
ERROR_INVALID_NAME | The specified service name is invalid.
ERROR_INVALID_PARAMETER | A parameter that was specified is invalid.
ERROR_INVALID_SERVICE_ACCOUNT | The user account name specified in the lpServiceStartName parameter does not exist.
ERROR_SERVICE_EXISTS | The specified service already exists in this database.

Remarks

The CreateService function creates a service object and installs it in the service control manager database by creating a key with the same name as the service under the following registry key:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services

Information specified for this function is saved as values under this key. Setup programs and the service itself can create subkeys under this key for any service specific information.

The returned handle is only valid for the process that called CreateService. It can be closed by calling the CloseServiceHandle function.

For example, see Installing a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, ChangeServiceConfig, CloseServiceHandle, ControlService, DeleteService, EnumDependentServices, OpenSCManager, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, SetServiceObjectSecurity, StartService


DeleteService

The DeleteService function marks the specified service for deletion from the service control manager database.

BOOL DeleteService(
  SC_HANDLE hService   // handle to service
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function, and it must have DELETE access.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes may be set by the service control manager. Others may be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with DELETE access.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_SERVICE_MARKED_FOR_DELETE | The specified service has already been marked for deletion.

Remarks

The DeleteService function marks a service for deletion from the service control manager database. The database entry is not removed until all open handles to the service have been closed by calls to the CloseServiceHandle function, and the service is not running. A running service is stopped by a call to the ControlService function with the SERVICE_CONTROL_STOP control code. If the service cannot be stopped, the database entry is removed when the system is restarted.

The service control manager deletes the service by deleting the service key and its subkeys from the registry.

For example, see Deleting a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, CloseServiceHandle, ControlService, CreateService, OpenService


EnumDependentServices

The EnumDependentServices function retrieves the name and status of each service that depends on the specified service; that is, the specified service must be running before the dependent services can run.

BOOL EnumDependentServices(
  SC_HANDLE hService,               // handle to service
  DWORD dwServiceState,             // service state
  LPENUM_SERVICE_STATUS lpServices, // status buffer
  DWORD cbBufSize,                  // size of status buffer
  LPDWORD pcbBytesNeeded,           // buffer size needed
  LPDWORD lpServicesReturned        // number of entries returned
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function, and it must have SERVICE_ENUMERATE_DEPENDENTS access.
dwServiceState
[in] Specifies the services to enumerate based on their state. This parameter must be one of the following values.
Value | Meaning
SERVICE_ACTIVE | Enumerates services that are in the following states: SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, and SERVICE_PAUSED.
SERVICE_INACTIVE | Enumerates services that are in the SERVICE_STOPPED state.
SERVICE_STATE_ALL | Combines the following states: SERVICE_ACTIVE and SERVICE_INACTIVE.

lpServices
[out] Pointer to an array of ENUM_SERVICE_STATUS structures that receives the name and service status information for each dependent service in the database. The buffer must be large enough to hold the structures, plus the strings to which their members point.

The order of the services in this array is the reverse of the start order of the services. In other words, the first service in the array is the one that would be started last, and the last service in the array is the one that would be started first.

cbBufSize
[in] Specifies the size, in bytes, of the buffer pointed to by the lpServices parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to store the array of service entries. The variable only receives this value if the buffer pointed to by lpServices is too small, indicated by function failure and the ERROR_MORE_DATA error; otherwise, the contents of pcbBytesNeeded are undefined.
lpServicesReturned
[out] Pointer to a variable that receives the number of service entries returned.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SERVICE_ENUMERATE_DEPENDENTS access.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_INVALID_PARAMETER | A parameter that was specified is invalid.
ERROR_MORE_DATA | The buffer pointed to by lpServices is not large enough. The function sets the variable pointed to by lpServicesReturned to the actual number of service entries stored into the buffer. The function sets the variable pointed to by pcbBytesNeeded to the number of bytes required to store all of the service entries.

Remarks

The returned services entries are ordered in the reverse order of the start order, with group order taken into account. If you need to stop the dependent services, you can use the order of entries written to the lpServices buffer to stop the dependent services in the proper order.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, CreateService, ENUM_SERVICE_STATUS, EnumServicesStatus, OpenService


EnumServicesStatus

The EnumServicesStatus function enumerates services in the specified service control manager database. The name and status of each service are provided.

This function has been superseded by the EnumServicesStatusEx function. It returns the same information EnumServicesStatus returns, plus the process identifier and additional information for the service. In addition, EnumServicesStatusEx enables you to enumerate services that belong to a specified group.

BOOL EnumServicesStatus(
  SC_HANDLE hSCManager,             // handle to SCM database
  DWORD dwServiceType,              // service type
  DWORD dwServiceState,             // service state
  LPENUM_SERVICE_STATUS lpServices, // status buffer
  DWORD cbBufSize,                  // size of status buffer
  LPDWORD pcbBytesNeeded,           // buffer size needed
  LPDWORD lpServicesReturned,       // number of entries returned
  LPDWORD lpResumeHandle            // next entry
);

Parameters

hSCManager
[in] Handle to the service control manager database. The OpenSCManager function returns this handle, which must have SC_MANAGER_ENUMERATE_SERVICE access.
dwServiceType
[in] Specifies the type of services to enumerate. This parameter can be one or more of the following values.
Value | Meaning
SERVICE_DRIVER | Enumerates services of type SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_WIN32 | Enumerates services of type SERVICE_WIN32_OWN_PROCESS and SERVICE_WIN32_SHARE_PROCESS.

dwServiceState
[in] Specifies the services to enumerate based on their state. This parameter must be one of the following values.
Value | Meaning
SERVICE_ACTIVE | Enumerates services that are in the following states: SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, and SERVICE_PAUSED.
SERVICE_INACTIVE | Enumerates services that are in the SERVICE_STOPPED state.
SERVICE_STATE_ALL | Combines the following states: SERVICE_ACTIVE and SERVICE_INACTIVE.

lpServices
[out] Pointer to a buffer that contains an array of ENUM_SERVICE_STATUS structures that receive the name and service status information for each service in the database. The buffer must be large enough to hold the structures, plus the strings to which their members point.
cbBufSize
[in] Specifies the size, in bytes, of the buffer pointed to by the lpServices parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to return the remaining service entries.
lpServicesReturned
[out] Pointer to a variable that receives the number of service entries returned.
lpResumeHandle
[in/out] Pointer to a variable that, on input, specifies the starting point of enumeration. You must set this value to zero the first time this function is called. On output, this value is zero if the function succeeds. However, if the function returns zero and the GetLastError function returns ERROR_MORE_DATA, this value is used to indicate the next service entry to be read when the function is called to retrieve the additional data.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SC_MANAGER_ENUMERATE_SERVICE access.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_INVALID_PARAMETER | A parameter that was specified is invalid.
ERROR_MORE_DATA | There are more service entries than would fit into the lpServices buffer. The actual number of service entries written to lpServices is returned in the lpServicesReturned parameter. The number of bytes required to get the remaining entries is returned in the pcbBytesNeeded parameter. The remaining services can be enumerated by additional calls to EnumServicesStatus with the lpResumeHandle parameter indicating the next service to read.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, EnumDependentServices, EnumServicesStatusEx, ENUM_SERVICE_STATUS, OpenSCManager


EnumServicesStatusEx

The EnumServicesStatusEx function enumerates services in the specified service control manager database. The name and status of each service are provided, along with additional data based on the specified information level.

This function supersedes the EnumServicesStatus function. It returns the same information EnumServicesStatus returns, plus the process identifier and additional information for the service. In addition, EnumServicesStatusEx enables you to enumerate services that belong to a specified group.

BOOL EnumServicesStatusEx (
  SC_HANDLE hSCManager,       // handle to SCM database
  SC_ENUM_TYPE InfoLevel,     // information level
  DWORD dwServiceType,        // service type
  DWORD dwServiceState,       // service state
  LPBYTE lpServices,          // status buffer
  DWORD cbBufSize,            // size of status buffer
  LPDWORD pcbBytesNeeded,     // buffer size needed
  LPDWORD lpServicesReturned, // number of entries returned
  LPDWORD lpResumeHandle,     // next entry
  LPCTSTR pszGroupName        // load-order group name
);

Parameters

hSCManager
[in] Handle to the service control manager database. The OpenSCManager function returns this handle, which must have SC_MANAGER_ENUMERATE_SERVICE access.
InfoLevel
[in] Specifies which service attributes are to be returned. Use SC_ENUM_PROCESS_INFO to retrieve the name and service status information for each service in the database. The lpServices parameter is a pointer to a buffer that receives an array of ENUM_SERVICE_STATUS_PROCESS structures. The buffer must be large enough to hold the structures as well as the strings to which their members point.

Currently, no other information levels are defined.

dwServiceType
[in] Specifies the type of services to enumerate. This parameter can be one or more of the following values.
Value | Meaning
SERVICE_DRIVER | Enumerates services of type SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_WIN32 | Enumerates services of type SERVICE_WIN32_OWN_PROCESS and SERVICE_WIN32_SHARE_PROCESS.

dwServiceState
[in] Specifies the services to enumerate based on their state. This parameter can be one of the following values.
Value | Meaning
SERVICE_ACTIVE | Enumerates services that are in the following states: SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_RUNNING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING, and SERVICE_PAUSED.
SERVICE_INACTIVE | Enumerates services that are in the SERVICE_STOPPED state.
SERVICE_STATE_ALL | Combines the SERVICE_ACTIVE and SERVICE_INACTIVE states.

lpServices
[out] Pointer to the buffer that receives the status information. The format of this data depends on the value of the InfoLevel parameter.
cbBufSize
[in] Specifies the size, in bytes, of the buffer pointed to by the lpServices parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to return the remaining service entries.
lpServicesReturned
[out] Pointer to a variable that receives the number of service entries returned.
lpResumeHandle
[in/out] Pointer to a variable that, on input, specifies the starting point of enumeration. You must set this value to zero the first time the EnumServicesStatusEx function is called. On output, this value is zero if the function succeeds. However, if the function returns zero and the GetLastError function returns ERROR_MORE_DATA, this value indicates the next service entry to be read when the EnumServicesStatusEx function is called to retrieve the additional data.
pszGroupName
[in] Specifies a load-order group name. If this parameter is a string, the only services enumerated are those that belong to the group that has the name specified by the string. If this parameter is an empty string, only services that do not belong to any group are enumerated. If this parameter is NULL, group membership is ignored and all services are enumerated.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError. The following errors may be returned.

Error code | Meaning
ERROR_ACCESS_DENIED | The handle was not opened with SC_MANAGER_ENUMERATE_SERVICE access.
ERROR_MORE_DATA | The buffer is too small. Not all data in the active database could be returned. The pcbBytesNeeded parameter contains the number of bytes required to receive the remaining entries.
ERROR_INVALID_PARAMETER | An illegal parameter value was used.
ERROR_INVALID_HANDLE | The handle is invalid.
ERROR_INVALID_LEVEL | The InfoLevel parameter contains an unsupported value.
ERROR_SHUTDOWN_IN_PROGRESS | The system is shutting down; this function cannot be called.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows 2000.

See Also

Services Overview, Service Functions, ENUM_SERVICE_STATUS_PROCESS


GetServiceDisplayName

The GetServiceDisplayName function retrieves the display name of the specified service.

BOOL GetServiceDisplayName(
  SC_HANDLE hSCManager,  // handle to SCM database
  LPCTSTR lpServiceName, // service name
  LPTSTR lpDisplayName,  // display name
  LPDWORD lpcchBuffer    // size of display name buffer
);

Parameters

hSCManager
[in] Handle to a service control manager database, as returned by the OpenSCManager function.
lpServiceName
[in] Pointer to a null-terminated string that specifies the service name. This name is the same as the service's registry key name.
lpDisplayName
[out] Pointer to a null-terminated string that receives the service's display name. If the function fails, this buffer will contain an empty string.
lpcchBuffer
[in/out] Pointer to a variable that specifies the size, in TCHARs, of the buffer pointed to by lpDisplayName. On output, this variable receives the size, in TCHARs, of the service's display name, excluding the NULL terminator.

If the buffer pointed to by lpDisplayName is too small to contain the display name, the function does not store it. When the function returns, lpcchBuffer contains the size of the service's display name, excluding the NULL terminator.

Return Values

If the functions succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

There are two names for a service: the service name and the display name. The service name is the name of the service's key in the registry. The display name is a user-friendly name that appears in the Services control panel application, and is used with the NET START command. To map the service name to the display name, use the GetServiceDisplayName function. To map the display name to the service name, use the GetServiceKeyName function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, GetServiceKeyName, OpenSCManager


GetServiceKeyName

The GetServiceKeyName function retrieves the service name of the specified service.

BOOL GetServiceKeyName(
  SC_HANDLE hSCManager,  // handle to SCM database
  LPCTSTR lpDisplayName, // display name
  LPTSTR lpServiceName,  // service name
  LPDWORD lpcchBuffer    // size of service name buffer
);

Parameters

hSCManager
[in] Handle to a computer's service control manager database, as returned by OpenSCManager.
lpDisplayName
[in] Pointer to a null-terminated string that specifies the service display name.
lpServiceName
[out] Pointer to a buffer that receives the service name. If the function fails, this buffer will contain an empty string.
lpcchBuffer
[in/out] Pointer to variable that specifies the size, in TCHARs, of the buffer pointed to by the lpServiceName parameter. When the function returns, this parameter contains the size, in TCHARs, of the service name, excluding the NULL terminator.

If the buffer pointed to by lpServiceName is too small to contain the service name, the function stores no data in it. When the function returns, lpcchBuffer contains the size of the service name, excluding the NULL terminator.

Return Values

If the functions succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

There are two names for a service: the service name and the display name. The service name is the name of the service's key in the registry. The display name is a user-friendly name that appears in the Services control panel application, and is used with the NET START command. To map the service name to the display name, use the GetServiceDisplayName function. To map the display name to the service name, use the GetServiceKeyName function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, GetServiceDisplayName, OpenSCManager


Handler

A Handler function is an application-defined callback function used with the RegisterServiceCtrlHandler function. A service program uses it as the control handler function of a particular service. The LPHANDLER_FUNCTION type defines a pointer to this function. Handler is a placeholder for the application-defined name.

This function has been superseded by the HandlerEx control handler function used with the RegisterServiceCtrlHandlerEx function. A service can use either control handler, but the new control handler supports user-defined context data and additional extended control codes.

VOID WINAPI Handler(
  DWORD fdwControl   // requested control code
);

Parameters

fdwControl
[in] The requested control code. This value can be one of the following control codes.
Control code | Description
SERVICE_CONTROL_CONTINUE | Notifies a paused service that it should resume.
SERVICE_CONTROL_INTERROGATE | Notifies a service that it should report its current status information to the service control manager.
SERVICE_CONTROL_NETBINDADD | Windows 2000 and later: Notifies a network service that there is a new component for binding. The service should bind to the new component.
SERVICE_CONTROL_NETBINDDISABLE | Windows 2000 and later: Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and remove the binding.
SERVICE_CONTROL_NETBINDENABLE | Windows 2000 and later: Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add the new binding.
SERVICE_CONTROL_NETBINDREMOVE | Windows 2000 and later: Notifies a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component.
SERVICE_CONTROL_PARAMCHANGE | Windows 2000 and later: Notifies a service that its startup parameters have changed. The service should reread its startup parameters.
SERVICE_CONTROL_PAUSE | Notifies a service that it should pause.
SERVICE_CONTROL_SHUTDOWN Notifies a service that the system is shutting down so the service can perform cleanup tasks.

For more information, see Remarks.
SERVICE_CONTROL_STOP | Notifies a service that it should stop.

This value can also be a user-defined control code, as described in the following table.
Control code | Meaning
Range 128 to 255. | The service defines the action associated with the control code.

Return Values

This function does not return a value.

Remarks

When a service is started, its ServiceMain function should immediately call the RegisterServiceCtrlHandler function to specify a Handler function to process control requests.

The control dispatcher in the main thread of a service process invokes the control handler function for the specified service whenever it receives a control request from the service control manager. After processing the control request, the control handler must call the SetServiceStatus function to report its current status to the service control manager.

The SERVICE_CONTROL_SHUTDOWN control code should only be processed by services that must absolutely clean up during shutdown, because there is a limited time (about 20 seconds) available for service shutdown. After this time expires, system shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not restarted or powered down), the service continues to run.

If the service needs more time to clean up, it should send STOP_PENDING status messages, along with a wait hint, so the service controller knows how long to wait before reporting to the system that service shutdown is complete. However, to prevent a service from stopping shutdown, there is a limit to how long the service controller will wait. To change this time limit, modify the WaitToKillServiceTimeout value in the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.

See Also

Services Overview, Service Functions, HandlerEx, RegisterServiceCtrlHandler, ServiceMain, SetServiceStatus


HandlerEx

A HandlerEx function is an application-defined callback function used with the RegisterServiceCtrlHandlerEx function. A service program can use it as the control handler function of a particular service.

The LPHANDLER_FUNCTION_EX type defines a pointer to this function. HandlerEx is a placeholder for the application-defined name.

This function supersedes the Handler control handler function used with the RegisterServiceCtrlHandler function. A service can use either control handler, but the new control handler supports user-defined context data and additional extended control codes.

DWORD WINAPI HandlerEx(
  DWORD dwControl,     // requested control code
  DWORD dwEventType,   // event type
  LPVOID lpEventData,  // event data
  LPVOID lpContext     // user-defined context data
);

Parameters

dwControl
[in] The requested control code. This value can be one of the following control codes.
Control code | Meaning
SERVICE_CONTROL_CONTINUE | Notifies a paused service that it should resume.
SERVICE_CONTROL_INTERROGATE | Notifies a service to report its current status information to the service control manager.
SERVICE_CONTROL_NETBINDADD | Windows 2000 and later: Notifies a network service that there is a new component for binding. The service should bind to the new component.
SERVICE_CONTROL_NETBINDDISABLE | Windows 2000 and later: Notifies a network service that one of its bindings has been disabled. The service should reread its binding information and remove the binding.
SERVICE_CONTROL_NETBINDENABLE | Windows 2000 and later: Notifies a network service that a disabled binding has been enabled. The service should reread its binding information and add the new binding.
SERVICE_CONTROL_NETBINDREMOVE | Windows 2000 and later: Notifies a network service that a component for binding has been removed. The service should reread its binding information and unbind from the removed component.
SERVICE_CONTROL_PARAMCHANGE | Windows 2000 and later: Notifies a service that service-specific startup parameters have changed. The service should reread its startup parameters.
SERVICE_CONTROL_PAUSE | Notifies a service that it should pause.
SERVICE_CONTROL_SHUTDOWN Notifies a service that the system is shutting down so the service can perform cleanup tasks.

For more information, see Remarks.
SERVICE_CONTROL_STOP | Notifies a service that it should stop.

This value can also be one of the following extended control codes. Note that these control codes are not supported by the Handler function.
Control code | Meaning
SERVICE_CONTROL_DEVICEEVENT | Windows 2000 and later: Notifies a service of device events. (The service must have registered to receive these notifications using the RegisterDeviceNotification function.)
SERVICE_CONTROL_HARDWAREPROFILECHANGE | Windows 2000 and later: Notifies a service that the computer's hardware profile has changed.
SERVICE_CONTROL_POWEREVENT | Windows 2000 and later: Notifies a service of system power events.
SERVICE_CONTROL_SESSIONCHANGE | Whistler: Notifies a service of session change events.

This value can also be a user-defined control code, as described in the following table.
Control code | Meaning
Range 128 to 255. | The service defines the action associated with the control code.

dwEventType
[in] The type of event that has occurred. This value is used if dwControl is SERVICE_CONTROL_DEVICEEVENT, SERVICE_CONTROL_HARDWAREPROFILECHANGE, SERVICE_CONTROL_POWEREVENT, or SERVICE_CONTROL_SESSIONCHANGE. Otherwise, this parameter is zero.

If dwControl is SERVICE_CONTROL_DEVICEEVENT, this parameter can be one of the following values:

  • DBT_DEVICEARRIVAL
  • DBT_DEVICEREMOVECOMPLETE
  • DBT_DEVICEQUERYREMOVE
  • DBT_DEVICEQUERYREMOVEFAILED
  • DBT_DEVICEREMOVEPENDING
  • DBT_CUSTOMEVENT

If dwControl is SERVICE_CONTROL_HARDWAREPROFILECHANGE, this parameter can be one of the following values:

  • DBT_CONFIGCHANGED
  • DBT_QUERYCHANGECONFIG
  • DBT_CONFIGCHANGECANCELED

If dwControl is SERVICE_CONTROL_POWEREVENT, this parameter can be one of the values specified in the wParam parameter of the WM_POWERBROADCAST message.

Whistler: If dwControl is SERVICE_CONTROL_SESSIONCHANGE, this parameter can be one of the values specified in the wParam parameter of the WM_WTSSESSION_CHANGE message.

lpEventData
[in] Additional device information, if required. The format of this data depends on the value of the dwControl and dwEventType parameters. If dwEventType is SERVICE_CONTROL_DEVICEEVENT, this data corresponds to the lParam parameter that applications receive as part of a WM_DEVICECHANGE message. If dwEventType is SERVICE_CONTROL_POWEREVENT, this data corresponds to the lParam parameter that applications receive as part of a WM_POWERBROADCAST message. If dwEventType is SERVICE_CONTROL_SESSIONCHANGE, this parameter is a WTSSESSION_NOTIFICATION structure.
lpContext
[in] The user-defined data passed from RegisterServiceCtrlHandlerEx. When multiple services share a process, the lpContext parameter can help identify the service.

Return Values

The return value for this function depends on the control code received. The rules for this return value are as follows.

  • If your service does not handle the control, return ERROR_CALL_NOT_IMPLEMENTED.
  • If your service handles SERVICE_CONTROL_DEVICEEVENT, return NO_ERROR to grant the request and an error code to deny the request.
  • If your service handles SERVICE_CONTROL_HARDWAREPROFILECHANGE, return NO_ERROR to grant the request and an error code to deny the request.
  • If your service handles SERVICE_CONTROL_POWEREVENT, return NO_ERROR to grant the request and an error code to deny the request.
  • For all other control codes your service handles, return NO_ERROR.

Remarks

When a service is started, its ServiceMain function should immediately call the RegisterServiceCtrlHandlerEx function to specify a HandlerEx function to process control requests. To specify the control codes to be accepted, use the SetServiceStatus and RegisterDeviceNotification functions.

The control dispatcher in the main thread of a service invokes the control handler function for the specified service whenever it receives a control request from the service control manager. After processing the control request, the control handler must call SetServiceStatus to report its current status to the service control manager.

The SERVICE_CONTROL_SHUTDOWN control code should only be processed by services that must absolutely clean up during shutdown, because there is a limited time (about 20 seconds) available for service shutdown. After this time expires, system shutdown proceeds regardless of whether service shutdown is complete. Note that if the system is left in the shutdown state (not restarted or powered down), the service continues to run.

If the service needs more time to clean up, it should send STOP_PENDING status messages, along with a wait hint, so the service controller knows how long to wait before reporting to the system that service shutdown is complete. However, to prevent a service from stopping shutdown, there is a limit to how long the service controller will wait. To change this time limit, modify the WaitToKillServiceTimeout value in the following registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.

See Also

Services Overview, Service Functions, RegisterDeviceNotification, RegisterServiceCtrlHandlerEx, ServiceMain, SetServiceStatus, WM_DEVICECHANGE, WM_POWERBROADCAST, WM_WTSSESSION_CHANGE, WTSSESSION_NOTIFICATION


LockServiceDatabase

The LockServiceDatabase function requests ownership of the service control manager database lock. Only one process can own the lock at any given time.

SC_LOCK LockServiceDatabase(
  SC_HANDLE hSCManager   // handle to SCM database
);

Parameters

hSCManager
[in] Handle to the service control manager database. The OpenSCManager function returns this handle, which must have SC_MANAGER_LOCK access.

Return Values

If the function succeeds, the return value is a lock to the specified service control manager database.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error code can be set by the service control manager. Other error codes can be set by registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SC_MANAGER_LOCK access.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_SERVICE_DATABASE_LOCKED | The database is locked.

Remarks

A lock is a protocol used by setup and configuration programs and the service control manager to serialize access to the service tree in the registry. The only time the service control manager requests ownership of the lock is when it is starting a service.

Acquiring the SCM database lock prevents the service control manager from starting a service until the lock is released. For example, a program that must configure several related services before any of them starts should call LockServiceDatabase before configuring the first service. Similarly, a program that must call both ChangeServiceConfig and ChangeServiceConfig2 for a particular service before it starts should call LockServiceDatabase before calling either function.

A call to the StartService function to start a service in a locked database fails. No other service control manager functions are affected by a lock.

The lock is held until the SC_LOCK handle is specified in a subsequent call to the UnlockServiceDatabase function. If a process that owns a lock terminates, the service control manager automatically cleans up and releases ownership of the lock.

For example, see Changing a Service Configuration.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, ChangeServiceConfig, OpenSCManager, QueryServiceLockStatus, SetServiceObjectSecurity, StartService, UnlockServiceDatabase


NotifyBootConfigStatus

The NotifyBootConfigStatus function reports the boot status to the service control manager. It is used by boot verification programs. This function can be called only by a process running in the LocalSystem or Administrator's account.

BOOL NotifyBootConfigStatus(
  BOOL BootAcceptable   // boot status
);

Parameters

BootAcceptable
[in] Specifies whether the configuration used when booting the system is acceptable. If the value is TRUE, the system saves the configuration as the last-known good configuration. If the value is FALSE, the system immediately reboots, using the previously saved last-known good configuration.

Return Values

If the BootAcceptable parameter is FALSE, the function does not return.

If the last-known good configuration was successfully saved, the return value is nonzero.

If an error occurs, the return value is zero. To get extended error information, call GetLastError.

The following error codes may be set by the service control manager. Other error codes may be set by the registry functions that are called by the service control manager to set parameters in the configuration registry.

Error code | Meaning
ERROR_ACCESS_DENIED | The user does not have permission to perform this operation. A hard-coded DACL associated with the service control manager object determines who can perform a NotifyBootConfigStatus operation. Only the system and members of the Adminstrators group can do so.

Remarks

Saving the configuration of a running system with this function is an acceptable method for saving the last-known good configuration. If the boot configuration is unacceptable, use this function to reboot the system using the existing last-known good configuration.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions


OpenSCManager

The OpenSCManager function establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.

SC_HANDLE OpenSCManager(
  LPCTSTR lpMachineName,   // computer name
  LPCTSTR lpDatabaseName,  // SCM database name
  DWORD dwDesiredAccess    // access type
);

Parameters

lpMachineName
[in] Pointer to a null-terminated string that specifies the name of the target computer. The target computer name must be prefixed by "\\". If the pointer is NULL or points to an empty string, the function connects to the service control manager on the local computer.
lpDatabaseName
[in] Pointer to a null-terminated string that specifies the name of the service control manager database to open. This parameter should be set to SERVICES_ACTIVE_DATABASE. If it is NULL, the SERVICES_ACTIVE_DATABASE database is opened by default.
dwDesiredAccess
[in] Specifies the access to the service control manager. Before granting the requested access, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service control manager. The SC_MANAGER_CONNECT access type is implicitly specified by calling this function. In addition, any or all of the following service control manager object access types can be specified.
Object access | Description
SC_MANAGER_ALL_ACCESS | Includes STANDARD_RIGHTS_REQUIRED, in addition to all of the access types listed in this table.
SC_MANAGER_CREATE_SERVICE | Enables calling of the CreateService function to create a service object and add it to the database.
SC_MANAGER_CONNECT | Enables connecting to the service control manager.
SC_MANAGER_ENUMERATE_SERVICE | Enables calling of the EnumServicesStatus function to list the services that are in the database.
SC_MANAGER_LOCK | Enables calling of the LockServiceDatabase function to acquire a lock on the database.
SC_MANAGER_QUERY_LOCK_STATUS | Enables calling of the QueryServiceLockStatus function to retrieve the lock status information for the database.

The dwDesiredAccess parameter can specify any or all of the following generic access types.
Generic access | Service manager access
GENERIC_READ | Combines the following access types: STANDARD_RIGHTS_READ, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS.
GENERIC_WRITE | Combines the following access types: STANDARD_RIGHTS_WRITE and SC_MANAGER_CREATE_SERVICE.
GENERIC_EXECUTE | Combines the following access types: STANDARD_RIGHTS_EXECUTE, SC_MANAGER_CONNECT, and SC_MANAGER_LOCK.

Return Values

If the function succeeds, the return value is a handle to the specified service control manager database.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the SCM. Other error codes can be set by the registry functions that are called by the SCM.

Error code | Meaning
ERROR_ACCESS_DENIED | The requested access was denied.
ERROR_DATABASE_DOES_NOT_EXIST | The specified database does not exist.
ERROR_INVALID_PARAMETER | A specified parameter is invalid.

Remarks

When a process uses the OpenSCManager function to open a handle to a service control manager database, the system performs a security check before granting the requested access. All processes are permitted SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access to all service control manager databases. This enables any process to open a service control manager database handle that it can use in the OpenService, EnumServicesStatus, and QueryServiceLockStatus functions. Only processes with Administrator privileges are able to open a database handle used by the CreateService and LockServiceDatabase functions.

The returned handle is only valid for the process that called the OpenSCManager function. It can be closed by calling the CloseServiceHandle function.

For an example, see Opening an SCManager Database.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, CloseServiceHandle, CreateService, EnumServicesStatus, LockServiceDatabase, OpenService, QueryServiceLockStatus


OpenService

The OpenService function opens an existing service.

SC_HANDLE OpenService(
  SC_HANDLE hSCManager,  // handle to SCM database
  LPCTSTR lpServiceName, // service name
  DWORD dwDesiredAccess  // access
);

Parameters

hSCManager
[in] Handle to the service control manager database. The OpenSCManager function returns this handle.
lpServiceName
[in] Pointer to a null-terminated string that specifies the name of the service to open. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. Forward-slash (/) and backslash (\) are invalid service name characters.
dwDesiredAccess
[in] Specifies the access to the service. Before granting the requested access, the system checks the access token of the calling process against the discretionary access-control list of the security descriptor associated with the service object.

The STANDARD_RIGHTS_REQUIRED constant enables the following object access types.
Standard rights | Description
ACCESS_SYSTEM_SECURITY | Enables calling of the QueryServiceObjectSecurity or SetServiceObjectSecurity function to access the SACL. The proper way to obtain this access is to enable the SE_SECURITY_NAME privilege in the caller's current access token, open the handle for ACCESS_SYSTEM_SECURITY access, and then disable the privilege.
DELETE | Enables calling of the DeleteService function to delete the service.
READ_CONTROL | Enables calling of the QueryServiceObjectSecurity function to query the security descriptor of the service object.
WRITE_DAC | Enables calling of the SetServiceObjectSecurity function to modify the Dacl member of the service object's security descriptor.
WRITE_OWNER | Enables calling of the SetServiceObjectSecurity function to modify the Owner and Group members of the service object's security descriptor.

You can specify any or all of the following service object access types.
Object access | Description
SERVICE_ALL_ACCESS | Includes STANDARD_RIGHTS_REQUIRED in addition to all of the access types listed in this table.
SERVICE_CHANGE_CONFIG | Enables calling of the ChangeServiceConfig function to change the service configuration.
SERVICE_ENUMERATE_DEPENDENTS | Enables calling of the EnumDependentServices function to enumerate all the services dependent on the service.
SERVICE_INTERROGATE | Enables calling of the ControlService function to ask the service to report its status immediately.
SERVICE_PAUSE_CONTINUE | Enables calling of the ControlService function to pause or continue the service.
SERVICE_QUERY_CONFIG | Enables calling of the QueryServiceConfig function to query the service configuration.
SERVICE_QUERY_STATUS | Enables calling of the QueryServiceStatus function to query the status of the service.
SERVICE_START | Enables calling of the StartService function to start the service.
SERVICE_STOP | Enables calling of the ControlService function to stop the service.
SERVICE_USER_DEFINED_CONTROL | Enables calling of the ControlService function to specify a user-defined control code.

You can specify any of the following generic access types.
Generic access | Service access
GENERIC_READ | Combines the following access types: STANDARD_RIGHTS_READ, SERVICE_QUERY_CONFIG, SERVICE_QUERY_STATUS, and SERVICE_ENUMERATE_DEPENDENTS.
GENERIC_WRITE | Combines the following access types: STANDARD_RIGHTS_WRITE and SERVICE_CHANGE_CONFIG.
GENERIC_EXECUTE | Combines the following access types: STANDARD_RIGHTS_EXECUTE, SERVICE_START, SERVICE_STOP, SERVICE_PAUSE_CONTINUE, and SERVICE_USER_DEFINED_CONTROL.

Return Values

If the function succeeds, the return value is a handle to the service.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified service control manager database handle does not have access to the service.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_INVALID_NAME | The specified service name is invalid.
ERROR_SERVICE_DOES_NOT_EXIST | The specified service does not exist.

Remarks

The returned handle is only valid for the process that called OpenService. It can be closed by calling the CloseServiceHandle function.

For an example, see Starting a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, ChangeServiceConfig, CloseServiceHandle, ControlService, CreateService, DeleteService, EnumDependentServices, OpenSCManager, QueryServiceConfig, QueryServiceObjectSecurity, QueryServiceStatus, SetServiceObjectSecurity, StartService


QueryServiceConfig

The QueryServiceConfig function retrieves the configuration parameters of the specified service. Optional configuration parameters are available using the QueryServiceConfig2 function.

BOOL QueryServiceConfig(
  SC_HANDLE hService,                     // handle to service
  LPQUERY_SERVICE_CONFIG lpServiceConfig, // buffer
  DWORD cbBufSize,                        // size of buffer
  LPDWORD pcbBytesNeeded                  // bytes needed
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function, and it must have SERVICE_QUERY_CONFIG access.
lpServiceConfig
[out] Pointer to a buffer that receives the service configuration information. The format of the data is a QUERY_SERVICE_CONFIG structure.
cbBufSize
[in] Specifies the size, in bytes, of the buffer pointed to by the lpServiceConfig parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to return all the configuration information if the function fails with the error ERROR_INSUFFICIENT_BUFFER.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SERVICE_QUERY_CONFIG access.
ERROR_INSUFFICIENT_BUFFER | There is more service configuration information than would fit into the lpServiceConfig buffer. The number of bytes required to get all the information is returned in the pcbBytesNeeded parameter. Nothing is written to the lpServiceConfig buffer.
ERROR_INVALID_HANDLE | The specified handle is invalid.

Remarks

The QueryServiceConfig function returns the service configuration information kept in the registry for a particular service. This configuration information is first set by a service control program using the CreateService function. This information may have been updated by a service configuration program using the ChangeServiceConfig function.

If the service was running when the configuration information was last changed, the information returned by QueryServiceConfig will not reflect the current configuration of the service. Instead, it will reflect the configuration of the service when it is next run. The DisplayName key is an exception to this. When the DisplayName key is changed, it takes effect immediately, regardless of whether the service is running.

For an example, see Querying a Service's Configuration.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, ChangeServiceConfig, CreateService, OpenService, QUERY_SERVICE_CONFIG, QueryServiceConfig2, QueryServiceObjectSecurity, QueryServiceStatus


QueryServiceConfig2

The QueryServiceConfig2 function retrieves the optional configuration parameters of the specified service.

BOOL QueryServiceConfig2(
  SC_HANDLE hService,     // handle to service
  DWORD dwInfoLevel,      // information level
  LPBYTE lpBuffer,        // buffer
  DWORD cbBufSize,        // size of buffer
  LPDWORD pcbBytesNeeded  // bytes needed
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function and must have the SERVICE_QUERY_CONFIG access right.
dwInfoLevel
[in] Specifies the configuration information to query. This parameter can have one of the following values.
Value | Meaning
SERVICE_CONFIG_DESCRIPTION | The lpBuffer parameter is a pointer to a SERVICE_DESCRIPTION structure.
SERVICE_CONFIG_FAILURE_ACTIONS | The lpBuffer parameter is a pointer to a SERVICE_FAILURE_ACTIONS structure.

lpBuffer
[out] Pointer to the buffer that receives the service configuration information. The format of this data depends on the value of the dwInfoLevel parameter.
cbBufSize
[in] Specifies the size, in bytes, of the structure pointed to by the lpBuffer parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to return the configuration information, if the function fails with the error ERROR_INSUFFICIENT_BUFFER.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The QueryServiceConfig2 function returns the optional configuration information stored in the service control manager database for the specified service. You can change this configuration information by using the ChangeServiceConfig2 function.

You can change and query additional configuration information using the ChangeServiceConfig and QueryServiceConfig functions, respectively.

For an example, see Querying a Service's Configuration.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows 2000.

See Also

Services Overview, Service Functions, ChangeServiceConfig, ChangeServiceConfig2, CreateService, OpenService, QueryServiceConfig, SERVICE_DESCRIPTION, SERVICE_FAILURE_ACTIONS


QueryServiceLockStatus

The QueryServiceLockStatus function retrieves the lock status of the specified service control manager database.

BOOL QueryServiceLockStatus(
  SC_HANDLE hSCManager,                     // handle to SCM database
  LPQUERY_SERVICE_LOCK_STATUS lpLockStatus, // buffer
  DWORD cbBufSize,                          // size of buffer
  LPDWORD pcbBytesNeeded                    // bytes needed
);

Parameters

hSCManager
[in] Handle to the service control manager database. The OpenSCManager function returns this handle, which must have SC_MANAGER_QUERY_LOCK_STATUS access.
lpLockStatus
[out] Pointer to a QUERY_SERVICE_LOCK_STATUS structure that receives the lock status of the specified database is returned, plus the strings to which its members point.
cbBufSize
[in] Specifies the size, in bytes, of the buffer pointed to by the lpLockStatus parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to return all the lock status information, if the function fails.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SC_MANAGER_QUERY_LOCK_STATUS access.
ERROR_INSUFFICIENT_BUFFER | There is more lock status information than would fit into the lpLockStatus buffer. The number of bytes required to get all the information is returned in the pcbBytesNeeded parameter. Nothing is written to the lpLockStatus buffer.
ERROR_INVALID_HANDLE | The specified handle is invalid.

Remarks

The QueryServiceLockStatus function returns a QUERY_SERVICE_LOCK_STATUS structure that indicates whether the specified database is locked. If the database is locked, the structure provides the account name of the user that owns the lock and the length of time that the lock has been held.

A process calls the LockServiceDatabase function to acquire ownership of a service control manager database lock and the UnlockServiceDatabase function to release the lock.

For an example, see Changing A Service Configuration.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, LockServiceDatabase, OpenSCManager, QUERY_SERVICE_LOCK_STATUS, UnlockServiceDatabase


QueryServiceStatus

The QueryServiceStatus function retrieves the current status of the specified service.

This function has been superseded by the QueryServiceStatusEx function. QueryServiceStatusEx returns the same information QueryServiceStatus returns, with the addition of the process identifier and additional information for the service.

BOOL QueryServiceStatus(
  SC_HANDLE hService,               // handle to service
  LPSERVICE_STATUS lpServiceStatus  // service status
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or the CreateService function, and it must have SERVICE_QUERY_STATUS access.
lpServiceStatus
[out] Pointer to a SERVICE_STATUS structure that receives the status information.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SERVICE_QUERY_STATUS access.
ERROR_INVALID_HANDLE | The specified handle is invalid.

Remarks

The QueryServiceStatus function returns the most recent service status information reported to the service control manager. If the service just changed its status, it may not have updated the service control manager yet. Applications can find out the current service status by interrogating the service directly using the ControlService function with the SERVICE_CONTROL_INTERROGATE control code.

For an example, see Starting a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, ControlService, CreateService, OpenService, QueryServiceStatusEx, SERVICE_STATUS, SetServiceStatus


QueryServiceStatusEx

The QueryServiceStatusEx function retrieves the current status of the specified service based on the specified information level.

This function supersedes the QueryServiceStatus function. QueryServiceStatusEx returns the same information QueryServiceStatus returns, with the addition of the process identifier and additional information for the service.

BOOL QueryServiceStatusEx(
  SC_HANDLE hService,       // handle to service
  SC_STATUS_TYPE InfoLevel, // information level
  LPBYTE lpBuffer,          // buffer
  DWORD cbBufSize,          // size of buffer
  LPDWORD pcbBytesNeeded    // bytes needed
);

Parameters

hService
[in] Handle to the service. This handle is returned by the CreateService or OpenService function, and it must have SERIVCE_QUERY_STATUS access.
InfoLevel
[in] Specifies which service attributes are to be returned. Use SC_STATUS_PROCESS_INFO to retrieve the service status information. The lpBuffer parameter is a pointer to a SERVICE_STATUS_PROCESS structure.

Currently, no other information levels are defined.

lpBuffer
[out] Pointer to the buffer that receives the status information. The format of this data depends on the value of the InfoLevel parameter.
cbBufSize
[in] Specifies the size, in bytes, of the buffer pointed to by the lpBuffer parameter.
pcbBytesNeeded
[out] Pointer to a variable that receives the number of bytes needed to store all status information, if the function fails with the error ERROR_INSUFFICIENT_BUFFER.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError. The following errors can be returned.

Error code | Meaning
ERROR_INVALID_HANDLE | The handle is invalid.
ERROR_ACCESS_DENIED | The handle was not opened with SERVICE_QUERY_STATUS access.
ERROR_INSUFFICIENT_BUFFER | The buffer is too small for the SERVICE_STATUS_PROCESS structure. Nothing was written to the structure.
ERROR_INVALID_PARAMETER | The cbSize member of SERVICE_STATUS_PROCESS is not valid.
ERROR_INVALID_LEVEL | The InfoLevel parameter contains an unsupported value.
ERROR_SHUTDOWN_IN_PROGRESS | The system is shutting down; this function cannot be called.

Remarks

The QueryServiceStatusEx function returns the most recent service status information reported to the service control manager. If the service just changed its status, it may not have updated the service control manager yet. Applications can find the current service status by querying the service directly by using the ControlService function with the SERVICE_CONTROL_INTERROGATE control code.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, SERVICE_STATUS_PROCESS


RegisterServiceCtrlHandler

A service calls the RegisterServiceCtrlHandler function to register a function to handle its service control requests.

This function has been superseded by the RegisterServiceCtrlHandlerEx function. A service can use either function, but the new function supports user-defined context data, and the new handler function supports additional extended control codes.

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(
  LPCTSTR lpServiceName,             // service name
  LPHANDLER_FUNCTION lpHandlerProc   // handler function
);

Parameters

lpServiceName
[in] Pointer to a null-terminated string that specifies the name of the service run by the calling thread. This is the service name that the service control program specified in the CreateService function when creating the service.

If the service type is SERVICE_WIN32_OWN_PROCESS, the function does not verify that the specified name is valid, because there is only one registered service in the process.

lpHandlerProc
[in] Pointer to the handler function to be registered. For more information, see Handler.

Return Values

If the function succeeds, the return value is a service status handle.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_INVALID_NAME | The specified service name is invalid.
ERROR_SERVICE_DOES_NOT_EXIST | The specified service does not exist.

Remarks

The ServiceMain function of a new service should immediately call the RegisterServiceCtrlHandler function to register a control handler function with the control dispatcher. This enables the control dispatcher to invoke the specified function when it receives control requests for this service. The threads of the calling process can use the service status handle returned by this function to identify the service in subsequent calls to the SetServiceStatus function.

The RegisterServiceCtrlHandler function must be called before the first SetServiceStatus call because RegisterServiceCtrlHandler returns a service status handle for the caller to use so that no other service can inadvertently set this service status. In addition, the control handler must be in place to receive control requests by the time the service specifies the controls it accepts through the SetServiceStatus function.

When the control handler function is invoked with a control request, it must call SetServiceStatus to notify the service control manager of its current status, regardless of whether the status of the service has changed.

The service status handle does not have to be closed.

For an example, see Writing a ServiceMain Function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, CreateService, Handler, RegisterServiceCtrlHandlerEx, ServiceMain, SetServiceStatus


RegisterServiceCtrlHandlerEx

A service calls the RegisterServiceCtrlHandlerEx function to register a function to handle its service control requests.

This function supersedes the RegisterServiceCtrlHandler function. A service can use either function, but the new function supports user-defined context data, and the new handler function supports additional extended control codes.

SERVICE_STATUS_HANDLE RegisterServiceCtrlHandlerEx(
  LPCTSTR lpServiceName,                // name of service
  LPHANDLER_FUNCTION_EX lpHandlerProc,  // handler function
  LPVOID lpContext                      // user data
);

Parameters

lpServiceName
[in] Pointer to a null-terminated string that specifies the name of the service run by the calling thread. This is the service name that the service control program specified in the CreateService function when creating the service.
lpHandlerProc
[in] Pointer to the handler function to be registered. For more information, see HandlerEx.
lpContext
[in] User-defined data. This parameter, which is passed to the handler function, can help identify the service when multiple services share a process.

Return Values

If the function succeeds, the return value is a service status handle.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_INVALID_NAME | The specified service name is invalid.
ERROR_SERVICE_DOES_NOT_EXIST | The specified service does not exist.

Remarks

The ServiceMain function of a new service should immediately call the RegisterServiceCtrlHandlerEx function to register a control handler function with the control dispatcher. This enables the control dispatcher to invoke the specified function when it receives control requests for this service. The threads of the calling process can use the service status handle returned by this function to identify the service in subsequent calls to the SetServiceStatus function.

The RegisterServiceCtrlHandlerEx function must be called before the first SetServiceStatus call because RegisterServiceCtrlHandlerEx returns a service status handle for the caller to use so that no other service can inadvertently set this service status. In addition, the control handler must be in place to receive control requests by the time the service specifies the controls it accepts through the SetServiceStatus function.

When the control handler function is invoked with a control request, it must call SetServiceStatus to notify the service control manager of its current status, regardless of whether the status of the service has changed.

The service status handle does not have to be closed.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows 2000.

See Also

Services Overview, Service Functions, CreateService, HandlerEx, ServiceMain, SetServiceStatus


ServiceMain

A ServiceMain function is the entry point for a service.

The LPSERVICE_MAIN_FUNCTION type defines a pointer to this callback function. ServiceMain is a placeholder for an application-defined function name.

VOID WINAPI ServiceMain(
  DWORD dwArgc,     // number of arguments
  LPTSTR *lpszArgv  // array of arguments
);

Parameters

dwArgc
[in] Specifies the number of arguments in the lpszArgv array.
lpszArgv
[in] Pointer to an array of pointers to null-terminated argument strings. The first argument in the array is the name of the service, and subsequent arguments are any strings passed to the service by the process that called the StartService function to start the service.

Return Values

This function does not return a value.

Remarks

A service program can start one or more services. A service process has a SERVICE_TABLE_ENTRY structure for each service that it can start. The structure specifies the service name and a pointer to the ServiceMain function for that service.

When the service control manager receives a request to start a service, it starts the service process (if it is not already running). The main thread of the service process calls the StartServiceCtrlDispatcher function with a pointer to an array of SERVICE_TABLE_ENTRY structures. Then the service control manager sends a start request to the service control dispatcher for this service process. The service control dispatcher creates a new thread to execute the ServiceMain function of the service being started.

The ServiceMain function should immediately call the RegisterServiceCtrlHandlerEx function to specify a HandlerEx function to handle control requests. Next, it should call the SetServiceStatus function to send status information to the service control manager. After these calls, the function completes the initialization tasks of the service, and waits for the service to terminate.

A ServiceMain function does not return until its services are ready to terminate.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.

See Also

Services Overview, Service Functions, HandlerEx, RegisterServiceCtrlHandlerEx, SetServiceStatus, SERVICE_TABLE_ENTRY, StartServiceCtrlDispatcher


SetServiceBits

The SetServiceBits function registers a service type with the service control manager and the Server service. The Server service can then announce the registered service type as one it currently supports. The NetServerGetInfo and NetServerEnum functions obtain a specified machine's supported service types.

BOOL SetServiceBits(
  SERVICE_STATUS_HANDLE hServiceStatus, // service status handle
  DWORD dwServiceBits,                  // service type
  BOOL bSetBitsOn,                      // set or clear
  BOOL bUpdateImmediately               // update type
);

Parameters

hServiceStatus
[in] Handle to the status information structure for the service. A service obtains the handle by calling the RegisterServiceCtrlHandlerEx function.
dwServiceBits
[in] A set of bit flags that specifies a service type.

Certain bit flags (0xC00F3F7B) are reserved for use by Microsoft. The SetServiceBits function fails with the error ERROR_INVALID_DATA if any of these bit flags are set in dwServiceBits. The following bit flags are reserved for use by Microsoft.
Reserved bit flag | Value
SV_TYPE_WORKSTATION | 0x00000001
SV_TYPE_SERVER | 0x00000002
SV_TYPE_DOMAIN_CTRL | 0x00000008
SV_TYPE_DOMAIN_BAKCTRL | 0x00000010
SV_TYPE_TIME_SOURCE | 0x00000020
SV_TYPE_AFP | 0x00000040
SV_TYPE_DOMAIN_MEMBER | 0x00000100
SV_TYPE_PRINTQ_SERVER | 0x00000200
SV_TYPE_DIALIN_SERVER | 0x00000400
SV_TYPE_XENIX_SERVER | 0x00000800
SV_TYPE_SERVER_UNIX | 0x00000800
SV_TYPE_NT | 0x00001000
SV_TYPE_WFW | 0x00002000
SV_TYPE_POTENTIAL_BROWSER | 0x00010000
SV_TYPE_BACKUP_BROWSER | 0x00020000
SV_TYPE_MASTER_BROWSER | 0x00040000
SV_TYPE_DOMAIN_MASTER | 0x00080000
SV_TYPE_LOCAL_LIST_ONLY | 0x40000000
SV_TYPE_DOMAIN_ENUM | 0x80000000

Certain bit flags (0x00300084) are defined by Microsoft, but are not specifically reserved for systems software. The following are these bit flags.
Bit-flag constant | Value
SV_TYPE_SV_TYPE_SQLSERVER | 0x00000004
SV_TYPE_NOVELL | 0x00000080
SV_TYPE_DOMAIN_CTRL | 0x00100000
SV_TYPE_DOMAIN_BAKCTRL | 0x00200000

Certain bit flags (0x3FC0C000) are not defined by Microsoft, and their use is not coordinated by Microsoft. Developers of applications that use these bits should be aware that other applications can also use them, thus creating a conflict. The following are these bit flags.
Conflict bit flag | Value
0x00004000 | 0x02000000
0x00008000 | 0x04000000
0x00400000 | 0x08000000
0x00800000 | 0x10000000
0x01000000 | 0x20000000

bSetBitsOn
[in] Specifies whether the function is to set or clear the bit flags that are set in dwServiceBit. If this value is TRUE, the bits are to be set. If this value is FALSE, the bits are to be cleared.
bUpdateImmediately
[in] Specifies whether the Server service is to perform an immediate update, announcing the new service type. If this value is TRUE, the update is to be performed immediately. If this value is FALSE, the update will not be performed immediately.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Header: Declared in Lmserver.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, NetServerGetInfo, NetServerEnum, RegisterServiceCtrlHandlerEx, SetServiceStatus


SetServiceStatus

The SetServiceStatus function updates the service control manager's status information for the calling service.

BOOL SetServiceStatus(
  SERVICE_STATUS_HANDLE hServiceStatus, // service status handle
  LPSERVICE_STATUS lpServiceStatus      // status buffer
);

Parameters

hServiceStatus
[in] Handle to the status information structure for the current service. This handle is returned by the RegisterServiceCtrlHandlerEx function.
lpServiceStatus
[in] Pointer to the SERVICE_STATUS structure the contains the latest status information for the calling service.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_INVALID_DATA | The specified service status structure is invalid.
ERROR_INVALID_HANDLE | The specified handle is invalid.

Remarks

A ServiceMain function first calls the RegisterServiceCtrlHandlerEx function to get the service's SERVICE_STATUS_HANDLE. Then it immediately calls the SetServiceStatus function to notify the service control manager of its SERVICE_START_PENDING status.

When a service receives a control request, the service's Handler function must call SetServiceStatus, even if the service's status did not change. A service can also use this function at any time and by any thread of the service to notify the service control manager of status changes. Examples of such unsolicited status updates include:

  • Checkpoint updates that occur when the service is in transition from one state to another (that is, SERVICE_START_PENDING).
  • Fatal error updates that occur when the service must stop due to a recoverable error.

A service can call this function only after it has called RegisterServiceCtrlHandlerEx to get a service status handle.

For an example, see Writing a ServiceMain Function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, HandlerEx, RegisterServiceCtrlHandlerEx, SERVICE_STATUS, ServiceMain, SetServiceBits


StartService

The StartService function starts a service.

BOOL StartService(
  SC_HANDLE hService,            // handle to service
  DWORD dwNumServiceArgs,        // number of arguments
  LPCTSTR* lpServiceArgVectors   // array of arguments
);

Parameters

hService
[in] Handle to the service. This handle is returned by the OpenService or CreateService function, and it must have SERVICE_START access.
dwNumServiceArgs
[in] Specifies the number of argument strings in the lpServiceArgVectors array. If lpServiceArgVectors is NULL, this parameter can be zero.
lpServiceArgVectors
[in] Pointer to an array of pointers to null-terminated argument strings passed to a service. Driver services do not receive these arguments. If no arguments are passed to the service being started, this parameter can be NULL. The service accesses these arguments through its ServiceMain function. The first argument (argv[0]) is the name of the service by default, followed by the arguments, if any, in the lpServiceArgVectors array.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Others can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_ACCESS_DENIED | The specified handle was not opened with SERVICE_START access.
ERROR_INVALID_HANDLE | The specified handle is invalid.
ERROR_PATH_NOT_FOUND | The service binary file could not be found.
ERROR_SERVICE_ALREADY_RUNNING | An instance of the service is already running.
ERROR_SERVICE_DATABASE_LOCKED | The database is locked.
ERROR_SERVICE_DEPENDENCY_DELETED | The service depends on a service that does not exist or has been marked for deletion.
ERROR_SERVICE_DEPENDENCY_FAIL | The service depends on another service that has failed to start.
ERROR_SERVICE_DISABLED | The service has been disabled.
ERROR_SERVICE_LOGON_FAILED | The service could not be logged on. This error occurs if the service was started from an account that does not have the "Log on as a service" right.
ERROR_SERVICE_MARKED_FOR_DELETE | The service has been marked for deletion.
ERROR_SERVICE_NO_THREAD | A thread could not be created for the service.
ERROR_SERVICE_REQUEST_TIMEOUT | The process for the service was started, but it did not call StartServiceCtrlDispatcher, or the thread that called StartServiceCtrlDispatcher may be blocked in a control handler function.

Remarks

When a driver service is started, the StartService function does not return until the device driver has finished initializing.

When a service is started, the service control manager spawns the service process, if necessary. If the specified service shares a process with other services, the required process may already exist. The StartService function does not wait for the first status update from the new service, because it can take a while. Instead, it returns when the service control manager receives notification from the service control dispatcher that the ServiceMain thread for this service was created successfully.

The service control manager sets the following default status values before returning from StartService:

  • Current state of the service is set to SERVICE_START_PENDING.
  • Controls accepted is set to none (zero).
  • The CheckPoint value is set to zero.
  • The WaitHint time is set to 2 seconds.

The calling process can determine if the new service has finished its initialization by calling the QueryServiceStatus function periodically to query the service's status.

A service cannot call StartService during initialization. The reason is that the service control manager locks the service control database during initialization, so a call to StartService will block. Once the service reports to the service control manager that it has successfully started, it can call StartService.

For an example, see Starting a Service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, ControlService, CreateService, OpenService, QueryServiceStatus, ServiceMain


StartServiceCtrlDispatcher

The StartServiceCtrlDispatcher function connects the main thread of a service process to the service control manager, which causes the thread to be the service control dispatcher thread for the calling process.

BOOL StartServiceCtrlDispatcher(
  CONST LPSERVICE_TABLE_ENTRY lpServiceTable   // service table
);

Parameters

lpServiceTable
[in] Pointer to an array of SERVICE_TABLE_ENTRY structures containing one entry for each service that can execute in the calling process. The members of the last entry in the table must have NULL values to designate the end of the table.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error code can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_INVALID_DATA | The specified dispatch table contains entries that are not in the proper format.
ERROR_SERVICE_ALREADY_RUNNING | Windows 2000 and later: The process has already called StartServiceCtrlDispatcher. Each process can call StartServiceCtrlDispatcher only one time.

Remarks

When the service control manager starts a service process, it waits for the process to call the StartServiceCtrlDispatcher function. The main thread of a service process should make this call as soon as possible after it starts up. If StartServiceCtrlDispatcher succeeds, it connects the calling thread to the service control manager and does not return until all running services in the process have terminated. The service control manager uses this connection to send control and service start requests to the main thread of the service process. The main thread acts as a dispatcher by invoking the appropriate HandlerEx function to handle control requests, or by creating a new thread to execute the appropriate ServiceMain function when a new service is started.

The lpServiceTable parameter contains an entry for each service that can run in the calling process. Each entry specifies the ServiceMain function for that service. For SERVICE_WIN32_SHARE_PROCESS services, each entry must contain the name of a service. This name is the service name that was specified by the CreateService function when the service was installed. For SERVICE_WIN32_OWN_PROCESS services, the service name in the table entry is ignored.

If a service runs in its own process, the main thread of the service process should immediately call StartServiceCtrlDispatcher. All initialization tasks are done in the service's ServiceMain function when the service is started.

If multiple services share a process and some common process-wide initialization needs to be done before any ServiceMain function is called, the main thread can do the work before calling StartServiceCtrlDispatcher, as long as it takes less than 30 seconds. Otherwise, another thread must be created to do the process-wide initialization, while the main thread calls StartServiceCtrlDispatcher and becomes the service control dispatcher. Any service-specific initialization should still be done in the individual service main functions.

For an example, see Writing a ServiceMain Function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Services Overview, Service Functions, ControlService, HandlerEx, ServiceMain, SERVICE_TABLE_ENTRY


UnlockServiceDatabase

The UnlockServiceDatabase function unlocks a service control manager database by releasing the specified lock.

BOOL UnlockServiceDatabase(
  SC_LOCK ScLock   // SCM database lock
);

Parameters

ScLock
[in] Specifies a lock obtained from a previous call to the LockServiceDatabase function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

The following error codes can be set by the service control manager. Other error codes can be set by the registry functions that are called by the service control manager.

Error code | Meaning
ERROR_INVALID_SERVICE_LOCK | The specified lock is invalid.

For an example, see Changing A Service Configuration.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Library: Use Advapi32.lib.

See Also

Services Overview, Service Functions, LockServiceDatabase, QueryServiceLockStatus


Service Structures

The following structures are used with services.

ENUM_SERVICE_STATUS
ENUM_SERVICE_STATUS_PROCESS
QUERY_SERVICE_CONFIG
QUERY_SERVICE_LOCK_STATUS
SC_ACTION
SERVICE_DESCRIPTION
SERVICE_FAILURE_ACTIONS
SERVICE_STATUS
SERVICE_STATUS_PROCESS
SERVICE_TABLE_ENTRY


ENUM_SERVICE_STATUS

The ENUM_SERVICE_STATUS structure is used by the EnumDependentServices and EnumServicesStatus functions to return the name of a service in a service control manager database and to return information about that service.

typedef struct _ENUM_SERVICE_STATUS {
  LPTSTR lpServiceName;
  LPTSTR lpDisplayName;
  SERVICE_STATUS ServiceStatus;
} ENUM_SERVICE_STATUS, *LPENUM_SERVICE_STATUS;

Members

lpServiceName
Pointer to a null-terminated string that names a service in a service control manager database. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. A slash (/), backslash (\), comma, and space are invalid service name characters.
lpDisplayName
Pointer to a null-terminated string that is to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the Service Control Manager. Display name comparisons are always case-insensitive.
ServiceStatus
A SERVICE_STATUS structure that contains status information for the lpServiceName service.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, EnumDependentServices, EnumServicesStatus, SERVICE_STATUS


ENUM_SERVICE_STATUS_PROCESS

The ENUM_SERVICE_STATUS_PROCESS structure is used by the EnumServicesStatusEx function to return the name of a service in a service control manager database. The structure also returns information about the service.

typedef struct _ENUM_SERVICE_STATUS_PROCESS {
  LPTSTR  lpServiceName;
  LPTSTR  lpDisplayName;
  SERVICE_STATUS_PROCESS  ServiceStatusProcess;
} ENUM_SERVICE_STATUS_PROCESS, *LPENUM_SERVICE_STATUS_PROCESS;

Members

lpServiceName
Pointer to a null-terminated string that names a service in a service control manager database. The maximum string length is 256 characters. The service control manager database preserves the case of the characters, but service name comparisons are always case insensitive. A slash (/), backslash (\), comma, and space are invalid service name characters.
lpDisplayName
Pointer to a null-terminated string that a program, such as the Services program in Control Panel, uses to identify the service. This string has a maximum length of 256 characters. The case is preserved in the service control manager. Display name comparisons are always case-insensitive.
ServiceStatusProcess
A SERVICE_STATUS_PROCESS structure that contains status information for the lpServiceName service.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, EnumServicesStatusEx, SERVICE_STATUS_PROCESS


QUERY_SERVICE_CONFIG

The QUERY_SERVICE_CONFIG structure is used by the QueryServiceConfig function to return configuration information about an installed service.

typedef struct _QUERY_SERVICE_CONFIG {
  DWORD dwServiceType;
  DWORD dwStartType;
  DWORD dwErrorControl;
  LPTSTR lpBinaryPathName;
  LPTSTR lpLoadOrderGroup;
  DWORD dwTagId;
  LPTSTR lpDependencies;
  LPTSTR lpServiceStartName;
  LPTSTR lpDisplayName;
} QUERY_SERVICE_CONFIG, *LPQUERY_SERVICE_CONFIG;

Members

dwServiceType
The type of service. This member can be one of the following values.
Value | Meaning
SERVICE_FILE_SYSTEM_DRIVER | The service is a file system driver.
SERVICE_KERNEL_DRIVER | The service is a device driver.
SERVICE_WIN32_OWN_PROCESS | The service runs in its own process.
SERVICE_WIN32_SHARE_PROCESS | The service shares a process with other services.

If the value is SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, the following type may also be specified.
Value | Meaning
SERVICE_INTERACTIVE_PROCESS | The service can interact with the desktop.

dwStartType
When to start the service. This member can be one of the following values.
Value | Meaning
SERVICE_AUTO_START | Specifies a device driver or service started by the service control manager automatically during system startup.
SERVICE_BOOT_START | Specifies a device driver started by the system loader. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.
SERVICE_DEMAND_START | Specifies a device driver or service started by the service control manager when a process calls the StartService function.
SERVICE_DISABLED | Specifies a device driver or service that can no longer be started.
SERVICE_SYSTEM_START | Specifies a device driver started by the IoInitSystem function. This value is valid only if the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER.

dwErrorControl
The severity of the error if this service fails to start during startup, and determines the action taken by the startup program if failure occurs. This member can be one of the following values.
Value | Meaning
SERVICE_ERROR_IGNORE | The startup (boot) program logs the error but continues the startup operation.
SERVICE_ERROR_NORMAL | The startup program logs the error and displays a message box pop-up but continues the startup operation.
SERVICE_ERROR_SEVERE | The startup program logs the error. If the last-known good configuration is being started, the startup operation continues. Otherwise, the system is restarted with the last-known-good configuration.
SERVICE_ERROR_CRITICAL | The startup program logs the error, if possible. If the last-known good configuration is being started, the startup operation fails. Otherwise, the system is restarted with the last-known good configuration.

lpBinaryPathName
Pointer to a null-terminated string that contains the fully qualified path to the service binary file.
lpLoadOrderGroup
Pointer to a null-terminated string that names the load ordering group of which this service is a member. If the pointer is NULL or if it points to an empty string, the service does not belong to a group. The registry has a list of load ordering groups located at:

HKEY_LOCAL_MACHINE\System
\CurrentControlSet\Control\ServiceGroupOrder

The startup program uses this list to load groups of services in a specified order with respect to the other groups in the list. You can place a service in a group so that another service can depend on the group.

The order in which a service starts is determined by the following criteria:

  1. The order of groups in the registry's load-ordering group list. Services in groups in the load-ordering group list are started first, followed by services in groups not in the load-ordering group list and then services that do not belong to a group.
  2. The service's dependencies listed in the lpszDependencies parameter and the dependencies of other services dependent on the service.
dwTagId
A unique tag value for this service in the group specified by the lpLoadOrderGroup parameter. A value of zero indicates that the service has not been assigned a tag. You can use a tag for ordering service startup within a load order group by specifying a tag order vector in the registry located at:

HKEY_LOCAL_MACHINE\System\CurrentControlSet
\Control\GroupOrderList

Tags are only evaluated for SERVICE_KERNEL_DRIVER and SERVICE_FILE_SYSTEM_DRIVER type services that have SERVICE_BOOT_START or SERVICE_SYSTEM_START start types.

lpDependencies
Pointer to an array of null-separated names of services or load ordering groups that must start before this service. The array is doubly null-terminated. If the pointer is NULL or if it points to an empty string, the service has no dependencies. If a group name is specified, it must be prefixed by the SC_GROUP_IDENTIFIER (defined in the WINSVC.H file) character to differentiate it from a service name, because services and service groups share the same name space. Dependency on a service means that this service can only run if the service it depends on is running. Dependency on a group means that this service can run if at least one member of the group is running after an attempt to start all members of the group.
lpServiceStartName
Pointer to a null-terminated string. If the service type is SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, this name is the account name in the form of "DomainName\Username", which the service process will be logged on as when it runs. If the account belongs to the built-in domain, ".\Username" can be specified. If this member is NULL, the service is to be logged on as the LocalSystem account.

If the service type is SERVICE_KERNEL_DRIVER or SERVICE_FILE_SYSTEM_DRIVER, this name is the driver object name (that is, \FileSystem\Rdr or \Driver\Xns) which the input and output (I/O) system uses to load the device driver. If this member is NULL, the driver is to be run with a default object name created by the I/O system, based on the service name.

lpDisplayName
Pointer to a null-terminated string that is to be used by user interface programs to identify the service. This string has a maximum length of 256 characters. The name is case-preserved in the service control manager. Display name comparisons are always case-insensitive.

Remarks

The configuration information for a service is initially specified when the service is created by a call to the CreateService function. The information can be modified by calling the ChangeServiceConfig function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, ChangeServiceConfig, CreateService, QueryServiceConfig, StartService


QUERY_SERVICE_LOCK_STATUS

The QUERY_SERVICE_LOCK_STATUS structure is used by the QueryServiceLockStatus function to return information about the lock status of a service control manager database.

typedef struct _QUERY_SERVICE_LOCK_STATUS {
  DWORD fIsLocked;
  LPTSTR lpLockOwner;
  DWORD dwLockDuration;
} QUERY_SERVICE_LOCK_STATUS, *LPQUERY_SERVICE_LOCK_STATUS;

Members

fIsLocked
The lock status of the database. If this member is nonzero, the database is locked. If it is zero, the database is unlocked.
lpLockOwner
Pointer to a null-terminated string containing the name of the user who acquired the lock.
dwLockDuration
The time, in seconds, since the lock was first acquired.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, QueryServiceLockStatus


SC_ACTION

The SC_ACTION structure represents an action that the service control manager can perform.

typedef struct _SC_ACTION {
  SC_ACTION_TYPE  Type;
  DWORD           Delay;
} SC_ACTION, *LPSC_ACTION;

Members

Type
The action to be performed. This member can be one of the following values.
Value | Meaning
SC_ACTION_NONE | No action.
SC_ACTION_REBOOT | Reboot the computer.
SC_ACTION_RESTART | Restart the service.
SC_ACTION_RUN_COMMAND | Run a command.

Delay
The time to wait before performing the specified action, in milliseconds.

Remarks

This structure is used by the ChangeServiceConfig2 and QueryServiceConfig2 functions, in the SERVICE_FAILURE_ACTIONS structure.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.

See Also

Services Overview, Service Structures, ChangeServiceConfig2, QueryServiceConfig2, SERVICE_FAILURE_ACTIONS


SERVICE_DESCRIPTION

The SERVICE_DESCRIPTION structure represents a service description.

typedef struct _SERVICE_DESCRIPTION {
  LPTSTR       lpDescription;
} SERVICE_DESCRIPTION, *LPSERVICE_DESCRIPTION;

Members

lpDescription
Pointer to a description of the service. The string is limited to 1024 bytes. If this value is NULL, the description remains unchanged. If this value is an empty string (""), the current description is deleted.

Remarks

A description of NULL indicates no service description exists. The service description is NULL when the service is created.

The description is simply a comment that explains the purpose of the service. For example, for the DHCP service, you could use the description "Provides internet addresses for computer on your network."

You can set the description using the ChangeServiceConfig2 function. You can retrieve the description using the QueryServiceConfig2 function. The description is also displayed by the Services snap-in.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, ChangeServiceConfig2, QueryServiceConfig2


SERVICE_FAILURE_ACTIONS

The SERVICE_FAILURE_ACTIONS structure represents the action the service controller should take on each failure of a service. A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.

typedef struct _SERVICE_FAILURE_ACTIONS {
  DWORD       dwResetPeriod;
  LPTSTR       lpRebootMsg;
  LPTSTR       lpCommand;
  DWORD       cActions;
  SC_ACTION * lpsaActions;
} SERVICE_FAILURE_ACTIONS, *LPSERVICE_FAILURE_ACTIONS;

Members

dwResetPeriod
The length of time, in seconds, after which to reset the failure count to zero if there are no failures. Specify INFINITE to indicate that this value should never be reset.
lpRebootMsg
Message to broadcast to server users before rebooting in response to the SC_ACTION_REBOOT service controller action.

If this value is NULL, the reboot message is unchanged. If the value is an empty string (""), the reboot message is deleted and no message is broadcast.

lpCommand
Command line of the process for the CreateProcess function to execute in response to the SC_ACTION_RUN_COMMAND service controller action. This process runs under the same account as the service.

If this value is NULL, the command is unchanged. If the value is an empty string (""), the command is deleted and no program is run when the service fails.

cActions
Number of elements in the lpsaActions array.

If this value is 0, but lpsaActions is not NULL, the reset period and array of failure actions are deleted.

lpsaActions
Pointer to an array of SC_ACTION structures.

If this value is NULL, the cActions and dwResetPeriod members are ignored.

Remarks

The service control manager counts the number of times each service has failed since the system booted. The count is reset to 0 if the service has not failed for dwResetPeriod seconds. When the service fails for the Nth time, the service controller performs the action specified in element [N-1] of the lpsaActions array. If N is greater than cActions, the service controller repeats the last action in the array.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, ChangeServiceConfig2, CreateProcess, QueryServiceConfig2, SC_ACTION


SERVICE_STATUS

The SERVICE_STATUS structure contains information about a service. The ControlService, EnumDependentServices, EnumServicesStatus, and QueryServiceStatus functions use this structure to return information about a service. A service uses this structure in the SetServiceStatus function to report its current status to the service control manager.

typedef struct _SERVICE_STATUS {
  DWORD dwServiceType;
  DWORD dwCurrentState;
  DWORD dwControlsAccepted;
  DWORD dwWin32ExitCode;
  DWORD dwServiceSpecificExitCode;
  DWORD dwCheckPoint;
  DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;

Members

dwServiceType
The type of service. This member can be one of the following values.
Value | Meaning
SERVICE_FILE_SYSTEM_DRIVER | The service is a file system driver.
SERVICE_KERNEL_DRIVER | The service is a device driver.
SERVICE_WIN32_OWN_PROCESS | The service runs in its own process.
SERVICE_WIN32_SHARE_PROCESS | The service shares a process with other services.

If the service type is either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, the following type may also be specified.
Value | Meaning
SERVICE_INTERACTIVE_PROCESS | The service can interact with the desktop.

dwCurrentState
The current state of the service. This member can be one of the following values.
Value | Meaning
SERVICE_CONTINUE_PENDING | The service continue is pending.
SERVICE_PAUSE_PENDING | The service pause is pending.
SERVICE_PAUSED | The service is paused.
SERVICE_RUNNING | The service is running.
SERVICE_START_PENDING | The service is starting.
SERVICE_STOP_PENDING | The service is stopping.
SERVICE_STOPPED | The service is not running.

dwControlsAccepted
The control codes that the service will accept and process in its handler function (see Handler and HandlerEx). A user interface process can control a service by specifying a control command in the ControlService function. By default, all services accept the SERVICE_CONTROL_INTERROGATE value.

The following are the control codes.
Control code Meaning
SERVICE_ACCEPT_NETBINDCHANGE Windows 2000 and later: The service is a network component that can accept changes in its binding without being stopped and restarted.

This control code allows the service to receive SERVICE_CONTROL_NETBINDADD, SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE, and SERVICE_CONTROL_NETBINDDISABLE notifications.
SERVICE_ACCEPT_PARAMCHANGE Windows 2000 and later: The service can reread its startup parameters without being stopped and restarted.

This control code allows the service to receive SERVICE_CONTROL_PARAMCHANGE notifications.
SERVICE_ACCEPT_PAUSE_CONTINUE The service can be paused and continued.

This control code allows the service to receive SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE notifications.
SERVICE_ACCEPT_SHUTDOWN The service is notified when system shutdown occurs.

This control code allows the service to receive SERVICE_CONTROL_SHUTDOWN notifications. Note that ControlService cannot send this notification; only the system can send it.
SERVICE_ACCEPT_STOP The service can be stopped.

This control code allows the service to receive SERVICE_CONTROL_STOP notifications.

This value can also contain the following extended control codes, which are supported only by HandlerEx.
Control code | Meaning
SERVICE_ACCEPT_HARDWAREPROFILECHANGE | Windows 2000 and later: The service is notified when the computer's hardware profile has changed. This enables the system to send SERVICE_CONTROL_HARDWAREPROFILECHANGE notifications to the service.
SERVICE_ACCEPT_POWEREVENT | Windows 2000 and later: The service is notified when the computer's power status has changed. This enables the system to send SERVICE_CONTROL_POWEREVENT notifications to the service.
SERVICE_ACCEPT_SESSIONCHANGE | Whistler: The service is notified when the computer's session status has changed. This enables the system to send SERVICE_CONTROL_SESSIONCHANGE notifications to the service.

dwWin32ExitCode
A Win32 error code that the service uses to report an error that occurs when it is starting or stopping. To return an error code specific to the service, the service must set this value to ERROR_SERVICE_SPECIFIC_ERROR to indicate that the dwServiceSpecificExitCode member contains the error code. The service should set this value to NO_ERROR when it is running and on normal termination.
dwServiceSpecificExitCode
A service-specific error code that the service returns when an error occurs while the service is starting or stopping. This value is ignored unless the dwWin32ExitCode member is set to ERROR_SERVICE_SPECIFIC_ERROR.
dwCheckPoint
A value that the service increments periodically to report its progress during a lengthy start, stop, pause, or continue operation. For example, the service should increment this value as it completes each step of its initialization when it is starting up. The user interface program that invoked the operation on the service uses this value to track the progress of the service during a lengthy operation. This value is not valid and should be zero when the service does not have a start, stop, pause, or continue operation pending.
dwWaitHint
An estimate of the amount of time, in milliseconds, that the service expects a pending start, stop, pause, or continue operation to take before the service makes its next call to the SetServiceStatus function with either an incremented dwCheckPoint value or a change in dwCurrentState. If the amount of time specified by dwWaitHint passes, and dwCheckPoint has not been incremented, or dwCurrentState has not changed, the service control manager or service control program can assume that an error has occurred.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.

See Also

Services Overview, Service Structures, ControlService, EnumDependentServices, EnumServicesStatus, QueryServiceStatus, SetServiceStatus


SERVICE_STATUS_PROCESS

The SERVICE_STATUS_PROCESS structure contains information about a service. The EnumServicesStatusEx and QueryServiceStatusEx functions use this structure to return information about a service.

typedef struct _SERVICE_STATUS_PROCESS {
  DWORD  dwServiceType;
  DWORD  dwCurrentState;
  DWORD  dwControlsAccepted;
  DWORD  dwWin32ExitCode;
  DWORD  dwServiceSpecificExitCode;
  DWORD  dwCheckPoint;
  DWORD  dwWaitHint;
  DWORD  dwProcessId;
  DWORD  dwServiceFlags;
} SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;

Members

dwServiceType
The type of service. This member can be one of the following values.
Value | Meaning
SERVICE_FILE_SYSTEM_DRIVER | The service is a file system driver.
SERVICE_KERNEL_DRIVER | The service is a device driver.
SERVICE_WIN32_OWN_PROCESS | The service runs in its own process.
SERVICE_WIN32_SHARE_PROCESS | The service shares a process with other services.

If the service type is either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, the following type may also be specified.
Value | Meaning
SERVICE_INTERACTIVE_PROCESS | The service can interact with the desktop.

dwCurrentState
The current state of the service. This member can be one of the following values.
Value | Meaning
SERVICE_STOPPED | The service is not running.
SERVICE_START_PENDING | The service is starting.
SERVICE_STOP_PENDING | The service is stopping.
SERVICE_RUNNING | The service is running.
SERVICE_CONTINUE_PENDING | The service continue is pending.
SERVICE_PAUSE_PENDING | The service pause is pending.
SERVICE_PAUSED | The service is paused.

dwControlsAccepted
The control codes that the service will accept and process in its handler function (see Handler and HandlerEx). A user interface process can control a service by specifying a control command in the ControlService function. By default, all services accept the SERVICE_CONTROL_INTERROGATE value.

The following are the control codes.
Control code Meaning
SERVICE_ACCEPT_NETBINDCHANGE Windows 2000 and later: The service is a network component that can accept changes in its binding without being stopped and restarted.

This control code allows the service to receive SERVICE_CONTROL_NETBINDADD, SERVICE_CONTROL_NETBINDREMOVE, SERVICE_CONTROL_NETBINDENABLE, and SERVICE_CONTROL_NETBINDDISABLE notifications.
SERVICE_ACCEPT_PARAMCHANGE Windows 2000 and later: The service can reread its startup parameters without being stopped and restarted.

This control code allows the service to receive SERVICE_CONTROL_PARAMCHANGE notifications.
SERVICE_ACCEPT_PAUSE_CONTINUE The service can be paused and continued.

This control code allows the service to receive SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE notifications.
SERVICE_ACCEPT_SHUTDOWN The service is notified when system shutdown occurs.

This control code allows the service to receive SERVICE_CONTROL_SHUTDOWN notifications. Note that ControlService cannot send this notification; only the system can send it.
SERVICE_ACCEPT_STOP The service can be stopped.

This control code allows the service to receive SERVICE_CONTROL_STOP notifications.

This value can also contain the following extended control codes, which are supported only by HandlerEx. (Note that these control codes cannot be sent by ControlService.)
Control code | Meaning
SERVICE_ACCEPT_HARDWAREPROFILECHANGE | Windows 2000 and later: The service is notified when the computer's hardware profile has changed. This enables the system to send SERVICE_CONTROL_HARDWAREPROFILECHANGE notifications to the service.
SERVICE_ACCEPT_POWEREVENT | Windows 2000 and later: The service is notified when the computer's power status has changed. This enables the system to send SERVICE_CONTROL_POWEREVENT notifications to the service.
SERVICE_ACCEPT_SESSIONCHANGE | Whistler: The service is notified when the computer's session status has changed. This enables the system to send SERVICE_CONTROL_SESSIONCHANGE notifications to the service.

dwWin32ExitCode
A Win32 error code that the service uses to report an error that occurs when it is starting or stopping. To return an error code specific to the service, the service must set this value to ERROR_SERVICE_SPECIFIC_ERROR to indicate that the dwServiceSpecificExitCode member contains the error code. The service should set this value to NO_ERROR when it is running and when it terminates normally.
dwServiceSpecificExitCode
A service-specific error code that the service returns when an error occurs while the service is starting or stopping. This value is ignored unless the dwWin32ExitCode member is set to ERROR_SERVICE_SPECIFIC_ERROR.
dwCheckPoint
A value that the service increments periodically to report its progress during a lengthy start, stop, pause, or continue operation. For example, the service should increment this value as it completes each step of its initialization when it is starting up. The user interface program that invoked the operation on the service uses this value to track the progress of the service during a lengthy operation. This value is not valid and should be zero when the service does not have a start, stop, pause, or continue operation pending.
dwWaitHint
The estimated time required, in milliseconds, for a pending start, stop, pause, or continue operation. After the specified amount of time has elapsed, the service makes its next call to the SetServiceStatus function with either an incremented dwCheckPoint value or a change in dwCurrentState. If the amount of time specified by dwWaitHint passes, and dwCheckPoint has not been incremented, or dwCurrentState has not changed, the service control manager or service control program can assume that an error has occurred.
dwProcessId
The process identifier of the service.
dwServiceFlags
This member can be either of the following values.
Value | Meaning
0 The service is running in a process that is not a system process, or it is not running.

If the service is running in a process that is not a system process, dwProcessId is nonzero. If the service is not running, dwProcessId is zero.

SERVICE_RUNS_IN_SYSTEM_PROCESS | The service runs in a system process that must always be running.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Header: Declared in Winsvc.h; include Windows.h.

See Also

Services Overview, Service Structures, EnumServicesStatusEx, QueryServiceStatusEx


SERVICE_TABLE_ENTRY

The SERVICE_TABLE_ENTRY structure is used by the StartServiceCtrlDispatcher function to specify the ServiceMain function for a service that can run in the calling process.

typedef struct _SERVICE_TABLE_ENTRY {
  LPTSTR lpServiceName;
  LPSERVICE_MAIN_FUNCTION lpServiceProc;
} SERVICE_TABLE_ENTRY, *LPSERVICE_TABLE_ENTRY;

Members

lpServiceName
Pointer to a null-terminated string that names a service that can run in this service process. This string is ignored if the service is installed in the service control manager database as a SERVICE_WIN32_OWN_PROCESS service type. For a SERVICE_WIN32_SHARE_PROCESS service process, this string names the service that uses the ServiceMain function pointed to by the lpServiceProc member.
lpServiceProc
Pointer to a ServiceMain function.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Header: Declared in Winsvc.h; include Windows.h.
Unicode: Declared as Unicode and ANSI structures.

See Also

Services Overview, Service Structures, ServiceMain, StartServiceCtrlDispatcher


Synchronization

There are a variety of ways to coordinate multiple threads of execution. The functions described in this overview provide mechanisms that threads can use to synchronize access to a resource.

  • About Synchronization
  • Using Synchronization
  • Synchronization Reference


About Synchronization

To synchronize access to a resource, use one of the synchronization objects in one of the wait functions. The state of a synchronization object is either signaled or nonsignaled. The wait functions allow a thread to block its own execution until a specified nonsignaled object is set to the signaled state.

The following are other synchronization mechanisms:

  • overlapped input and output
  • asynchronous procedure calls
  • critical section objects
  • interlocked variable access


Wait Functions

The wait functions to allow a thread to block its own execution. The wait functions do not return until the specified criteria have been met. The type of wait function determines the set of criteria used. When a wait function is called, it checks whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the criteria to be met.

There are four types of wait functions:

  • single-object
  • multiple-object
  • alertable
  • registered

Single-object Wait Functions

The SignalObjectAndWait, WaitForSingleObject, and WaitForSingleObjectEx functions require a handle to one synchronization object. These functions return when one of the following occurs:

  • The specified object is in the signaled state.
  • The time-out interval elapses. The time-out interval can be set to INFINITE to specify that the wait will not time out.

The SignalObjectAndWait function enables the calling thread to atomically set the state of an object to signaled and wait for the state of another object to be set to signaled.

Multiple-object Wait Functions

The WaitForMultipleObjects, WaitForMultipleObjectsEx, MsgWaitForMultipleObjects, and MsgWaitForMultipleObjectsEx functions enable the calling thread to specify an array containing one or more synchronization object handles. These functions return when one of the following occurs:

  • The state of any one of the specified objects is set to signaled or the states of all objects have been set to signaled. You control whether one or all of the states will be used in the function call.
  • The time-out interval elapses. The time-out interval can be set to INFINITE to specify that the wait will not time out.

The MsgWaitForMultipleObjects and MsgWaitForMultipleObjectsEx function allow you to specify input event objects in the object handle array. This is done when you specify the type of input to wait for in the thread's input queue.

For example, a thread could use MsgWaitForMultipleObjects to block its execution until the state of a specified object has been set to signaled and there is mouse input available in the thread's input queue. The thread can use the GetMessage or PeekMessage function to retrieve the input.

When waiting for the states of all objects to be set to signaled, these multiple-object functions do not modify the states of the specified objects until the states of all objects have been set signaled. For example, the state of a mutex object can be signaled, but the calling thread does not get ownership until the states of the other objects specified in the array have also been set to signaled. In the meantime, some other thread may get ownership of the mutex object, thereby setting its state to nonsignaled.

Alertable Wait Functions

The MsgWaitForMultipleObjectsEx, SignalObjectAndWait, WaitForMultipleObjectsEx , and WaitForSingleObjectEx functions differ from the other wait functions in that they can optionally perform an alertable wait operation. In an alertable wait operation, the function can return when the specified conditions are met, but it can also return if the system queues an I/O completion routine or an APC for execution by the waiting thread. For more information about alertable wait operations and I/O completion routines, see Synchronization and Overlapped Input and Output. For more information about APCs, see Asynchronous Procedure Calls.

Registered Wait Functions

The RegisterWaitForSingleObject function differs from the other wait functions in that the wait operation is performed by a thread from the thread pool. When the specified conditions are met, the callback function is executed by a worker thread from the thread pool.

By default, a registered wait operation is a multiple-wait operation. The system resets the timer every time the event is signaled (or the time-out interval elapses) until you call the UnregisterWaitEx function to cancel the operation. To specify that a wait operation should be executed only once, set the dwFlags parameter of RegisterWaitForSingleObject to WT_EXECUTEONLYONCE.

Wait Functions and Synchronization Objects

The wait functions can modify the states of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. Wait functions can modify the states of synchronization objects as follows:

  • The count of a semaphore object decreases by one, and the state of the semaphore is set to nonsignaled if its count is zero.
  • The states of mutex, auto-reset event, and change-notification objects are set to nonsignaled.
  • The state of a synchronization timer is set to nonsignaled.
  • The states of manual-reset event, manual-reset timer, process, thread, and console input objects are not affected by a wait function.

Wait Functions and Creating Windows

You have to be careful when using the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. If you have a thread that uses a wait function with no time-out interval, the system will deadlock. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than the other wait functions.


Synchronization Objects

A synchronization object is an object whose handle can be specified in one of the wait functions to coordinate the execution of multiple threads. More than one process can have a handle to the same synchronization object, making interprocess synchronization possible.

The following object types are provided exclusively for synchronization.

Type | Description
Event | Notifies one or more waiting threads that an event has occurred. For more information, see Event Objects.
Mutex | Can be owned by only one thread at a time, enabling threads to coordinate mutually exclusive access to a shared resource. For more information, see Mutex Objects.
Semaphore | Maintains a count between zero and some maximum value, limiting the number of threads that are simultaneously accessing a shared resource. For more information, see Semaphore Objects.
Waitable timer | Notifies one or more waiting threads that a specified time has arrived. For more information, see Waitable Timer Objects.

Though available for other uses, the following objects can also be used for synchronization.

Object | Description
Change notification | Created by the FindFirstChangeNotification function, its state is set to signaled when a specified type of change occurs within a specified directory or directory tree. For more information, see File I/O.
Console input | Created when a console is created. The handle to console input is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function. Its state is set to signaled when there is unread input in the console's input buffer, and set to nonsignaled when the input buffer is empty. For more information about consoles, see Consoles and Character-Mode Support.
Job | Created by calling the CreateJobObject function. The state of a job object is set to signaled when all its processes are terminated because the specified end-of-job time limit has been exceeded. For more information about job objects, see Job Objects.
Process | Created by calling the CreateProcess function. Its state is set to nonsignaled while the process is running, and set to signaled when the process terminates. For more information about processes, see Processes and Threads.
Thread | Created when a new thread is created by calling the CreateProcess, CreateThread, or CreateRemoteThread function. Its state is set to nonsignaled while the thread is running, and set to signaled when the thread terminates. For more information about threads, see Processes and Threads.

In some circumstances, you can also use a file, named pipe, or communications device as a synchronization object; however, their use for this purpose is discouraged. Instead, use asynchronous I/O and wait on the event object set in the OVERLAPPED structure. It is safer to use the event object because of the confusion that can occur when multiple simultaneous overlapped operations are performed on the same file, named pipe, or communications device. In this situation, there is no way to know which operation caused the object's state to be signaled.

For additional information about I/O operations on files, named pipes, or communications, see Synchronization and Overlapped Input and Output.


Event Objects

An event object is a synchronization object whose state can be explicitly set to signaled by use of the SetEvent or PulseEvent function. Following are the two types of event object.

Object | Description
Manual-reset event | An event object whose state remains signaled until it is explicitly reset to nonsignaled by the ResetEvent function. While it is signaled, any number of waiting threads, or threads that subsequently specify the same event object in one of the wait functions, can be released.
Auto-reset event | An event object whose state remains signaled until a single waiting thread is released, at which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.

The event object is useful in sending a signal to a thread indicating that a particular event has occurred. For example, in overlapped input and output, the system sets a specified event object to the signaled state when the overlapped operation has been completed. A single thread can specify different event objects in several simultaneous overlapped operations, then use one of the multiple-object wait functions to wait for the state of any one of the event objects to be signaled.

A thread uses the CreateEvent function to create an event object. The creating thread specifies the initial state of the object and whether it is a manual-reset or auto-reset event object. The creating thread can also specify a name for the event object. Threads in other processes can open a handle to an existing event object by specifying its name in a call to the OpenEvent function. For additional information about names for mutex, event, semaphore, and timer objects, see Interprocess Synchronization.

A thread can use the PulseEvent function to set the state of an event object to signaled and then reset it to nonsignaled after releasing the appropriate number of waiting threads. For a manual-reset event object, all waiting threads are released. For an auto-reset event object, the function releases only a single waiting thread, even if multiple threads are waiting. If no threads are waiting, PulseEvent simply sets the state of the event object to nonsignaled and returns.


Mutex Objects

A mutex object is a synchronization object whose state is set to signaled when it is not owned by any thread, and nonsignaled when it is owned. Only one thread at a time can own a mutex object, whose name comes from the fact that it is useful in coordinating mutually exclusive access to a shared resource. For example, to prevent two threads from writing to shared memory at the same time, each thread waits for ownership of a mutex object before executing the code that accesses the memory. After writing to the shared memory, the thread releases the mutex object.

A thread uses the CreateMutex function to create a mutex object. The creating thread can request immediate ownership of the mutex object and can also specify a name for the mutex object. Threads in other processes can open a handle to an existing mutex object by specifying its name in a call to the OpenMutex function. For additional information about names for mutex, event, semaphore, and timer objects, see Interprocess Synchronization.

Any thread with a handle to a mutex object can use one of the wait functions to request ownership of the mutex object. If the mutex object is owned by another thread, the wait function blocks the requesting thread until the owning thread releases the mutex object using the ReleaseMutex function. The return value of the wait function indicates whether the function returned for some reason other than the state of the mutex being set to signaled.

Threads that are waiting for ownership of a mutex are placed in a first in, first out (FIFO) queue. Therefore, the first thread to wait on the mutex will be the first to receive ownership of the mutex, regardless of thread priority. However, kernel-mode APCs and events that suspend a thread will cause the system to remove the thread from the queue. When the thread resumes its wait for the mutex, it is placed at the end of the queue.

After a thread obtains ownership of a mutex, it can specify the same mutex in repeated calls to the wait-functions without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. To release its ownership under such circumstances, the thread must call ReleaseMutex once for each time that the mutex satisfied the conditions of a wait function.

If a thread terminates without releasing its ownership of a mutex object, the mutex object is considered to be abandoned. A waiting thread can acquire ownership of an abandoned mutex object, but the wait function's return value indicates that the mutex object is abandoned. It is best to assume that an abandoned mutex object indicates that an error has occurred and that any shared resource being protected by the mutex object is in an undefined state. If the thread proceeds as though the mutex object had not been abandoned, its "abandoned" flag is cleared when the thread releases its ownership. This restores normal behavior if a handle to the mutex object is subsequently specified in a wait function.


Semaphore Objects

A semaphore object is a synchronization object that maintains a count between zero and a specified maximum value. The count is decremented each time a thread completes a wait for the semaphore object and incremented each time a thread releases the semaphore. When the count reaches zero, no more threads can successfully wait for the semaphore object state to become signaled. The state of a semaphore is set to signaled when its count is greater than zero, and nonsignaled when its count is zero.

The semaphore object is useful in controlling a shared resource that can support a limited number of users. It acts as a gate that limits the number of threads sharing the resource to a specified maximum number. For example, an application might place a limit on the number of windows that it creates. It uses a semaphore with a maximum count equal to the window limit, decrementing the count whenever a window is created and incrementing it whenever a window is closed. The application specifies the semaphore object in call to one of the wait functions before each window is created. When the count is zero — indicating that the window limit has been reached — the wait function blocks execution of the window-creation code.

A thread uses the CreateSemaphore function to create a semaphore object. The creating thread specifies the initial count and the maximum value of the count for the object. The initial count must be neither less than zero nor greater than the maximum value. The creating thread can also specify a name for the semaphore object. Threads in other processes can open a handle to an existing semaphore object by specifying its name in a call to the OpenSemaphore function. For additional information about names for mutex, event, semaphore, and timer objects, see Interprocess Synchronization.

Threads that are waiting for a semaphore are placed in a first in, first out (FIFO) queue. Therefore, the first thread to wait on the semaphore will be the first to successfully complete the wait, regardless of thread priority. However, kernel-mode APCs and events that suspend a thread from waiting will cause the system to remove the thread from the queue. When the thread resumes its wait for the semaphore, it is placed at the end of the queue.

Each time one of the wait functions returns because the state of a semaphore was set to signaled, the count of the semaphore is decreased by one. The ReleaseSemaphore function increases a semaphore's count by a specified amount. The count can never be less than zero or greater than the maximum value.

The initial count of a semaphore is typically set to the maximum value. The count is then decremented from that level as the protected resource is consumed. Alternatively, you can create a semaphore with an initial count of zero to block access to the protected resource while the application is being initialized. After initialization, you can use ReleaseSemaphore to increment the count to the maximum value.

A thread that owns a mutex object can wait repeatedly for the same mutex object to become signaled without its execution becoming blocked. A thread that waits repeatedly for the same semaphore object, however, decrements the semaphore's count each time a wait operation is completed; the thread is blocked when the count gets to zero. Similarly, only the thread that owns a mutex can successfully call the ReleaseMutex function, though any thread can use ReleaseSemaphore to increase the count of a semaphore object.

A thread can decrement a semaphore's count more than once by repeatedly specifying the same semaphore object in calls to any of the wait functions. However, calling one of the multiple-object wait functions with an array that contains multiple handles of the same semaphore does not result in multiple decrements.


Timer Queues

The CreateTimerQueue function creates a queue for timers. Timers in this queue, known as timer-queue timers, are lightweight objects that enable you to specify a callback function to be called when the specified due time arrives. The wait operation is performed by a thread in the thread pool.

To add a timer to the queue, call the CreateTimerQueueTimer function. To update a timer-queue timer, call the ChangeTimerQueueTimer function. You can specify a callback function to be executed by a worker thread from the thread pool when the timer expires.

To cancel a pending timer, call the DeleteTimerQueueTimer function. When you are finished with the queue of timers, call the DeleteTimerQueueEx function to delete the timer queue. Any pending timers in the queue are canceled and deleted.


Waitable Timer Objects

A waitable timer object is a synchronization object whose state is set to signaled when the specified due time arrives. There are two types of waitable timers that can be created: manual-reset and synchronization. A timer of either type can also be a periodic timer.

Object | Description
manual-reset timer | A timer whose state remains signaled until SetWaitableTimer is called to establish a new due time.
synchronization timer | A timer whose state remains signaled until a thread completes a wait operation on the timer object.
periodic timer | A timer that is reactivated each time the specified period expires, until the timer is reset or canceled. A periodic timer is either a periodic manual-reset timer or a periodic synchronization timer.

A thread uses the CreateWaitableTimer function to create a timer object. Specify TRUE for the bManualReset parameter to create a manual-reset timer and FALSE to create a synchronization timer. The creating thread can specify a name for the timer object in the lpTimerName parameter. Threads in other processes can open a handle to an existing timer by specifying its name in a call to the OpenWaitableTimer function. Any thread with a handle to a timer object can use one of the wait functions to wait for the timer state to be set to signaled.

  • The thread calls the SetWaitableTimer function to activate the timer. Note the use of the following parameters for SetWaitableTimer:
  • Use the lpDueTime parameter to specify the time at which the timer is to be set to the signaled state. When a manual-reset timer is set to the signaled state, it remains in this state until SetWaitableTimer establishes a new due time. When a synchronization timer is set to the signaled state, it remains in this state until a thread completes a wait operation on the timer object.
  • Use the lPeriod parameter of the SetWaitableTimer function to specify the timer period. If the period is not zero, the timer is a periodic timer; it is reactivated each time the period expires, until the timer is reset or canceled. If the period is zero, the timer is not a periodic timer; it is signaled once and then deactivated.

A thread can use the CancelWaitableTimer function to set the timer to the inactive state. To reset the timer, call SetWaitableTimer. When you are finished with the timer object, call CloseHandle to close the handle to the timer object.


Interprocess Synchronization

Multiple processes can have handles to the same event, mutex, semaphore, or timer object, so these objects can be used to accomplish interprocess synchronization. The process that creates an object can use the handle returned by the creation function (CreateEvent, CreateMutex, CreateSemaphore, or CreateWaitableTimer). Other processes can open a handle to the object by using its name, or through inheritance or duplication.


Object Names

Named objects provide an easy way for processes to share object handles. Once a process has created a named event, mutex, semaphore, or timer object, other processes can use the name to call the appropriate function (OpenEvent, OpenMutex, OpenSemaphore, or OpenWaitableTimer) to open a handle to the object. Name comparison is case sensitive.

The names of event, semaphore, mutex, waitable timer, file-mapping, and job objects share the same name space. If you try to create an object using a name that is in use by an object of another type, the function fails and GetLastError returns ERROR_INVALID_HANDLE. Therefore, when creating named objects, use unique names and be sure to check function return values for duplicate-name errors.

If you try to create an object using a name that is in use by an object of same type, the function succeeds, returning a handle to the existing object, and GetLastError returns ERROR_ALREADY_EXISTS. For example, if the name specified in a call to the CreateMutex function matches the name of an existing mutex object, the function returns a handle to the existing object. In this case, the call to CreateMutex is equivalent to a call to the OpenMutex function. Having multiple processes use CreateMutex for the same mutex is therefore equivalent to having one process that calls CreateMutex while the other processes call OpenMutex, except that it eliminates the need to ensure that the creating process is started first. When using this technique for mutex objects, however, none of the calling processes should request immediate ownership of the mutex. If multiple processes do request immediate ownership, it can be difficult to predict which process actually gets the initial ownership.

Terminal Services: A Terminal Services environment has a global name space for events, semaphores, mutexes, waitable timers, file-mapping objects, and job objects. In addition, each Terminal Services client session has its own separate name space for these objects. Terminal Services client processes can use object names with a "Global\" or "Local\" prefix to explicitly create an object in the global or session name space. For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.


Object Inheritance

When you create a process with the CreateProcess function, you can specify that the process inherit handles to mutex, event, semaphore, or timer objects using the SECURITY_ATTRIBUTES structure. The handle inherited by the process has the same access to the object as the original handle. The inherited handle appears in the handle table of the created process, but you must communicate the handle value to the created process. You can do this by specifying the value as a command-line argument when you call CreateProcess. The created process then uses the GetCommandLine function to retrieve the command-line string and convert the handle argument into a usable handle. For more information, see Inheritance.


Object Duplication

The DuplicateHandle function creates a duplicate handle that can be used by another specified process. This method of sharing object handles is more complex than using named objects or inheritance. It requires communication between the creating process and the process into which the handle is duplicated. The necessary information (the handle value and process identifier) can be communicated by any of the interprocess communication methods, such as named pipes or named shared memory.


Synchronization Object Security and Access Rights

Windows NT/Windows 2000 security enables you to control access to event, mutex, semaphore, and waitable timer objects. Timer queues, interlocked variables, and critical section objects are not securable. For more information about security, see Access-Control Model.

You can specify a security descriptor for an interprocess synchronization object when you call the CreateEvent, CreateMutex, CreateSemaphore, or CreateWaitableTimer function. To get or set the security descriptor of an event, mutex, semaphore, or waitable timer object, call the GetNamedSecurityInfo, SetNamedSecurityInfo, GetSecurityInfo, or SetSecurityInfo functions.

The handles returned by CreateEvent, CreateMutex, CreateSemaphore, and CreateWaitableTimer have full access to the new object. When you call the OpenEvent, OpenMutex, OpenSemaphore, and OpenWaitableTimer functions, the system checks the requested access rights against the object's security descriptor.

The valid access rights for all interprocess synchronization objects include the DELETE, READ_CONTROL, SYNCHRONIZE, WRITE_DAC, and WRITE_OWNER standard access rights.

The following table lists the specific access rights for event objects.

Value | Meaning
EVENT_ALL_ACCESS | Specifies all possible access rights for an event object.
EVENT_MODIFY_STATE | Specifies modify state access, which is required for the ResetEvent and PulseEvent functions.

The following table lists the specific access rights for mutex objects.

Value | Meaning
MUTEX_ALL_ACCESS | Specifies all possible access rights for a mutex object.
MUTEX_MODIFY_STATE | Specifies modify state access, which is required for the ReleaseMutex function.

The following table lists the specific access rights for semaphore objects.

Value | Meaning
SEMAPHORE_ALL_ ACCESS | Specifies all possible access rights for a semaphore object.
SEMAPHORE_MODIFY_ STATE | Specifies modify state access, which is required for the ReleaseSemaphore function.

The following table lists the specific access rights for waitable timer objects.

Value | Meaning
TIMER_ALL_ACCESS | Specifies all possible access rights for a waitable timer object.
TIMER_MODIFY_STATE | Specifies modify state access, which is required for the SetWaitableTimer and CancelWaitableTimer functions.
TIMER_QUERY_STATE | Reserved for future use.

To read or write the SACL of an interprocess synchronization object, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see Access-Control Lists (ACLs) and SACL Access Right.


Synchronization and Overlapped Input and Output

You can perform either synchronous or asynchronous (or overlapped) I/O operations on files, named pipes, and serial communications devices. The WriteFile, ReadFile, DeviceIoControl, WaitCommEvent, ConnectNamedPipe, and TransactNamedPipe functions can be performed either synchronously or asynchronously. The ReadFileEx and WriteFileEx functions can be performed asynchronously only.

When a function is executed synchronously, it does not return until the operation has been completed. This means that the execution of the calling thread can be blocked for an indefinite period while it waits for a time-consuming operation to finish. Functions called for overlapped operation can return immediately, even though the operation has not been completed. This enables a time-consuming I/O operation to be executed in the background while the calling thread is free to perform other tasks. For example, a single thread can perform simultaneous I/O operations on different handles, or even simultaneous read and write operations on the same handle.

To synchronize its execution with the completion of the overlapped operation, the calling thread uses the GetOverlappedResult function or one of the wait functions to determine when the overlapped operation has been completed. You can also use the HasOverlappedIoCompleted macro to poll for completion.

To cancel all pending asynchronous I/O operations, use the CancelIo function. This function only cancels operations issued by the calling thread for the specified file handle.

Overlapped operations require a file, named pipe, or communications device that was created with the FILE_FLAG_OVERLAPPED flag. To call a function to perform an overlapped operation, the calling thread must specify a pointer to an OVERLAPPED structure. If this pointer is NULL, the function return value may incorrectly indicate that the operation completed. The OVERLAPPED structure must contain a handle to a manual-reset — not an auto-reset — event object. The system sets the state of the event object to nonsignaled when a call to the I/O function returns before the operation has been completed. The system sets the state of the event object to signaled when the operation has been completed.

When a function is called to perform an overlapped operation, it is possible that the operation will be completed before the function returns. When this happens, the results are handled as if the operation had been performed synchronously. If the operation was not completed, however, the function's return value is FALSE, and the GetLastError function returns ERROR_IO_PENDING.

A thread can manage overlapped operations by either of two methods:

  • Use the GetOverlappedResult function to wait for the overlapped operation to be completed.
  • Specify a handle to the OVERLAPPED structure's manual-reset event object in one of the wait functions and then call GetOverlappedResult after the wait function returns. The GetOverlappedResult function returns the results of the completed overlapped operation, and for functions in which such information is appropriate, it reports the actual number of bytes that were transferred.

When performing multiple simultaneous overlapped operations, the calling thread must specify an OVERLAPPED structure with a different manual-reset event object for each operation. To wait for any one of the overlapped operations to be completed, the thread specifies all the manual-reset event handles as wait criteria in one of the multiple-object wait functions. The return value of the multiple-object wait function indicates which manual-reset event object was signaled, so the thread can determine which overlapped operation caused the wait operation to be completed.

If no event object is specified in the OVERLAPPED structure, the system signals the state of the file, named pipe, or communications device when the overlapped operation has been completed. Thus, you can specify these handles as synchronization objects in a wait function, though their use for this purpose can be difficult to manage. When performing simultaneous overlapped operations on the same file, named pipe, or communications device, there is no way to know which operation caused the object's state to be signaled. It is safer to use a separate event object for each overlapped operation.

For examples that illustrate the use of overlapped operations, completion routines, and the GetOverlappedResult function, see Using Pipes.


Asynchronous Procedure Calls

An asynchronous procedure call (APC) is a function that executes asynchronously in the context of a particular thread. When an APC is queued to a thread, the system issues a software interrupt. The next time the thread is scheduled, it will run the APC function. APCs made by the system are called "kernel-mode APCs." APCs made by an application are called "user-mode APCs." A thread must be in an alertable state to run a user-mode APC.

Each thread has its own APC queue. An application queues an APC to a thread by calling the QueueUserAPC function. The calling thread specifies the address of an APC function in the call to QueueUserAPC. The queuing of an APC is a request for the thread to call the APC function.

When a user-mode APC is queued, the thread to which it is queued is not directed to call the APC function unless it is in an alertable state. A thread enters an alertable state when it calls the SleepEx, SignalObjectAndWait, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx, or WaitForSingleObjectEx function. Note that you can not use WaitForSingleObjectEx to wait on the handle to the object for which the APC is queued. Otherwise, when the asynchronous operation is completed, the handle is set to the signaled state and the thread is no longer in an alertable wait state, so the APC function will not be executed. However, the APC is still queued, so the APC function will be executed if you call another alertable wait function.

Note that the ReadFileEx, SetWaitableTimer, and WriteFileEx functions are implemented using an APC as the completion notification callback mechanism.


Critical Section Objects

Critical section objects provide synchronization similar to that provided by mutex objects, except that critical section objects can be used only by the threads of a single process. Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization. Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. There is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads.

The process is responsible for allocating the memory used by a critical section. Typically, this is done by simply declaring a variable of type CRITICAL_SECTION. Before the threads of the process can use it, initialize the critical section by using the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function.

A thread uses the EnterCriticalSection or TryEnterCriticalSection function to request ownership of a critical section. It uses the LeaveCriticalSection function to release ownership of a critical section. If the critical section object is currently owned by another thread, EnterCriticalSection waits indefinitely for ownership. In contrast, when a mutex object is used for mutual exclusion, the wait functions accept a specified time-out interval. The TryEnterCriticalSection function attempts to enter a critical section without blocking the calling thread.

Once a thread owns a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.

A thread uses the InitializeCriticalSectionAndSpinCount or SetCriticalSectionSpinCount function to specify a spin count for the critical section object. On single-processor systems, the spin count is ignored and the critical section spin count is set to 0. On multiprocessor systems, if the critical section is unavailable, the calling thread will spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation.

Any thread of the process can use the DeleteCriticalSection function to release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.

When a critical section object is owned, the only other threads affected are those waiting for ownership in a call to EnterCriticalSection. Threads that are not waiting are free to continue running.


Interlocked Variable Access

The interlocked functions provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

Simple reads and writes to properly-aligned 32-bit variables are atomic. In other words, when one thread is updating a 32-bit variable, you will not end up with only one portion of the variable updated; all 32 bits are updated in an atomic fashion. However, access is not guaranteed to be synchronized. If two threads are reading and writing from the same variable, you cannot determine if one thread will perform its read operation before the other performs its write operation.

The interlocked functions should be used to perform complex operations in an atomic manner. The InterlockedIncrement and InterlockedDecrement functions combine the operations of incrementing or decrementing the variable and checking the resulting value. This atomic operation is useful in a multitasking operating system, in which the system can interrupt one thread's execution to grant a slice of processor time to another thread. Without such synchronization, one thread could increment a variable but be interrupted by the system before it can check the resulting value of the variable. A second thread could then increment the same variable. When the first thread receives its next time slice, it will check the value of the variable, which has now been incremented not once but twice. The interlocked variable-access functions protect against this kind of error.

The InterlockedExchangePointer function atomically exchanges the values of the specified variables. The InterlockedExchangeAdd function combines two operations: adding two variables together and storing the result in one of the variables.

The InterlockedCompareExchangePointer function combines two operations: comparing two values and storing a third value in one of the variables, based on the outcome of the comparison.


Using Synchronization

  • Using named objects
  • Waiting for multiple objects
  • Waiting in a message loop
  • Using mutex objects
  • Using semaphore objects
  • Using event objects
  • Using critical section objects
  • Using timer queues
  • Using waitable timer objects


Using Named Objects

The following examples illustrate the use of object names by creating and opening named objects.

Mutex

The first process uses the CreateMutex function to create the mutex object. Note that the function succeeds even if there is an existing object with the same name.

// One process creates the mutex object.

HANDLE hMutex;
DWORD dwErr;

hMutex = CreateMutex(
    NULL,                  // no security descriptor
    FALSE,                 // mutex not owned
    "NameOfMutexObject");  // object name

if (hMutex == NULL)
    printf("CreateMutex error: %d\n", GetLastError() );
else
    if ( GetLastError() == ERROR_ALREADY_EXISTS )
        printf("CreateMutex opened existing mutex\n");
    else
        printf("CreateMutex created new mutex\n");

The second process uses the OpenMutex function to open a handle to the existing mutex. This function fails if a mutex object with the specified name does not exist. The access parameter requests full access to the mutex object, which is necessary for the handle to be used in any of the wait functions.

// Another process opens a handle to the existing mutex.

HANDLE hMutex;

hMutex = OpenMutex(
    MUTEX_ALL_ACCESS,      // request full access
    FALSE,                 // handle not inheritable
    "NameOfMutexObject");  // object name

if (hMutex == NULL)
    printf("OpenMutex error: %d\n", GetLastError() );

Semaphore

The following example uses the CreateSemaphore function to illustrate a named-object creation operation that fails if the object already exists.

HANDLE CreateNewSemaphore(LPSECURITY_ATTRIBUTES lpsa,
    LONG cInitial, LONG cMax, LPTSTR lpszName)
{
    HANDLE hSem;

// Create or open a named semaphore.

    hSem = CreateSemaphore(
        lpsa,         // security attributes
        cInitial,     // initial count
        cMax,         // maximum count
        lpszName);    // semaphore name

// Close handle, and return NULL if existing semaphore opened.

    if (hSem != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
    {
        CloseHandle(hSem);
        return NULL;
    }

// If new semaphore was created, return the handle.

    return hSem;
}


Waiting for Multiple Objects

The following example uses the CreateEvent function to create two event objects. It then uses the WaitForMultipleObjects function to wait for the state of one of the objects to be set to signaled.

HANDLE hEvents[2];
DWORD i, dwEvent;

// Create two event objects.

for (i = 0; i < 2; i++)
{
    hEvents[i] = CreateEvent(
        NULL,   // no security attributes
        FALSE,  // auto-reset event object
        FALSE,  // initial state is nonsignaled
        NULL);  // unnamed object
    if (hEvents[i] == NULL) {
        printf("CreateEvent error: %d\n", GetLastError() );
        ExitProcess(0);
    }
}

// The creating thread waits for other threads or processes
// to signal the event objects.

dwEvent = WaitForMultipleObjects(
    2,           // number of objects in array
    hEvents,     // array of objects
    FALSE,       // wait for any
    INFINITE);   // indefinite wait

// Return value indicates which event is signaled.

switch (dwEvent) {

    // hEvent[0] was signaled.
    case WAIT_OBJECT_0 + 0:
        // Perform tasks required by this event.
        break;

    // hEvent[1] was signaled.
    case WAIT_OBJECT_0 + 1:
        // Perform tasks required by this event.
        break;

    // Return value is invalid.
    default:
        printf("Wait error: %d\n", GetLastError());
        ExitProcess(0);
}


Waiting in a Message Loop

The following code fragment illustrates the use of the MsgWaitForMultipleObjects function in a message loop.

int MessageLoop (
    HANDLE* lphObjects,  // handles that need to be waited on
    int     cObjects     // number of handles to wait on
  )
{
    // The message loop lasts until we get a WM_QUIT message,
    // upon which we shall return from the function.
    while (TRUE)
    {
        // block-local variable
        DWORD result ;
        MSG msg ;

        // Read all of the messages in this next loop,
        // removing each message as we read it.
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            // If it's a quit message, we're out of here.
            if (msg.message == WM_QUIT)
                return 1;
            // Otherwise, dispatch the message.
            DispatchMessage(&msg);
        } // End of PeekMessage while loop.

        // Wait for any message sent or posted to this queue
        // or for one of the passed handles be set to signaled.
        result = MsgWaitForMultipleObjects(cObjects, lphObjects,
                 FALSE, INFINITE, QS_ALLINPUT);

        // The result tells us the type of event we have.
        if (result == (WAIT_OBJECT_0 + cObjects))
        {
            // New messages have arrived.
            // Continue to the top of the always while loop to
            // dispatch them and resume waiting.
            continue;
        }
        else
        {
            // One of the handles became signaled.
            DoStuff (result - WAIT_OBJECT_0) ;
        } // End of else clause.
    } // End of the always while loop.
} // End of function.


Using Mutex Objects

You can use a mutex object to protect a shared resource from simultaneous access by multiple threads or processes. Each thread must wait for ownership of the mutex before it can execute the code that accesses the shared resource. For example, if several threads share access to a database, the threads can use a mutex object to permit only one thread at a time to write to the database.

In the following example, a process uses the CreateMutex function to create a named mutex object or open a handle to an existing mutex object.

HANDLE hMutex;

// Create a mutex with no initial owner.

hMutex = CreateMutex(
    NULL,                       // no security attributes
    FALSE,                      // initially not owned
    "MutexToProtectDatabase");  // name of mutex

if (hMutex == NULL)
{
    // Check for error.
}

When a thread of this process writes to the database, as in the next example, it first requests ownership of the mutex. If it gets ownership, the thread writes to the database and then releases its ownership.

The example uses structured exception-handling syntax to ensure that the thread properly releases the mutex object. The __finally block of code is executed no matter how the __try block terminates (unless the __try block includes a call to the TerminateThread function). This prevents the mutex object from being abandoned inadvertently.

BOOL FunctionToWriteToDatabase(HANDLE hMutex)
{
    DWORD dwWaitResult;

    // Request ownership of mutex.

    dwWaitResult = WaitForSingleObject(
        hMutex,   // handle to mutex
        5000L);   // five-second time-out interval

    switch (dwWaitResult)
    {
        // The thread got mutex ownership.
        case WAIT_OBJECT_0:
            __try {
                // Write to the database.
            }

            __finally {
                // Release ownership of the mutex object.
                if (! ReleaseMutex(hMutex)) {
                    // Deal with error.
                }

            break;
        }

        // Cannot get mutex ownership due to time-out.
        case WAIT_TIMEOUT:
            return FALSE;

        // Got ownership of the abandoned mutex object.
        case WAIT_ABANDONED:
            return FALSE;
    }

    return TRUE;
}


Using Semaphore Objects

In the following example, a process uses a semaphore object to limit the number of windows it creates. First, it uses the CreateSemaphore function to create the semaphore and to specify initial and maximum counts.

HANDLE hSemaphore;
LONG cMax = 10;
LONG cPreviousCount;

// Create a semaphore with initial and max. counts of 10.

hSemaphore = CreateSemaphore(
    NULL,   // no security attributes
    cMax,   // initial count
    cMax,   // maximum count
    NULL);  // unnamed semaphore

if (hSemaphore == NULL)
{
    // Check for error.
}

Before any thread of the process creates a new window, it uses the WaitForSingleObject function to determine whether the semaphore's current count permits the creation of additional windows. The wait function's time-out parameter is set to zero, so the function returns immediately if the semaphore is nonsignaled.

DWORD dwWaitResult;

// Try to enter the semaphore gate.

dwWaitResult = WaitForSingleObject(
        hSemaphore,   // handle to semaphore
        0L);          // zero-second time-out interval

switch (dwWaitResult) {

    // The semaphore object was signaled.
    case WAIT_OBJECT_0:
        // OK to open another window.
        break;

    // Semaphore was nonsignaled, so a time-out occurred.
    case WAIT_TIMEOUT:
        // Cannot open another window.
        break;
}

When a thread closes a window, it uses the ReleaseSemaphore function to increment the semaphore's count.

// Increment the count of the semaphore.

if (!ReleaseSemaphore(
        hSemaphore,  // handle to semaphore
        1,           // increase count by one
        NULL) )      // not interested in previous count
{
    // Deal with the error.
}


Using Event Objects

Applications use event objects in a number of situations to notify a waiting thread of the occurrence of an event. For example, overlapped I/O operations on files, named pipes, and communications devices use an event object to signal their completion. For more information about the use of event objects in overlapped I/O operations, see Synchronization and Overlapped Input and Output.

In the following example, an application uses event objects to prevent several threads from reading from a shared memory buffer while a master thread is writing to that buffer. First, the master thread uses the CreateEvent function to create a manual-reset event object. The master thread sets the event object to nonsignaled when it is writing to the buffer and then resets the object to signaled when it has finished writing. Then it creates several reader threads and an auto-reset event object for each thread. Each reader thread sets its event object to signaled when it is not reading from the buffer.

#define NUMTHREADS 4

HANDLE hGlobalWriteEvent;

void CreateEventsAndThreads(void)
{
    HANDLE hReadEvents[NUMTHREADS], hThread;
    DWORD i, IDThread;

    // Create a manual-reset event object. The master thread sets
    // this to nonsignaled when it writes to the shared buffer.

    hGlobalWriteEvent = CreateEvent(
        NULL,         // no security attributes
        TRUE,         // manual-reset event
        TRUE,         // initial state is signaled
        "WriteEvent"  // object name
        );

    if (hGlobalWriteEvent == NULL) {
        // error exit
    }

    // Create multiple threads and an auto-reset event object
    // for each thread. Each thread sets its event object to
    // signaled when it is not reading from the shared buffer.

    for(i = 1; i <= NUMTHREADS; i++)
    {
        // Create the auto-reset event.
        hReadEvents[i] = CreateEvent(
            NULL,     // no security attributes
            FALSE,    // auto-reset event
            TRUE,     // initial state is signaled
            NULL);    // object not named

        if (hReadEvents[i] == NULL)
        {
            // Error exit.
        }

        hThread = CreateThread(NULL, 0,
            (LPTHREAD_START_ROUTINE) ThreadFunction,
            &hReadEvents[i],  // pass event handle
            0, &IDThread);
        if (hThread == NULL)
        {
            // Error exit.
        }
    }
}

Before the master thread writes to the shared buffer, it uses the ResetEvent function to set the state of hGlobalWriteEvent (an application-defined global variable) to nonsignaled. This blocks the reader threads from starting a read operation. The master then uses the WaitForMultipleObjects function to wait for all reader threads to finish any current read operations. When WaitForMultipleObjects returns, the master thread can safely write to the buffer. After it has finished, it sets hGlobalWriteEvent and all the reader-thread events to signaled, enabling the reader threads to resume their read operations.

VOID WriteToBuffer(VOID)
{
    DWORD dwWaitResult, i;

    // Reset hGlobalWriteEvent to nonsignaled, to block readers.

    if (! ResetEvent(hGlobalWriteEvent) )
    {
        // Error exit.
    }

    // Wait for all reading threads to finish reading.

    dwWaitResult = WaitForMultipleObjects(
        NUMTHREADS,   // number of handles in array
        hReadEvents,  // array of read-event handles
        TRUE,         // wait until all are signaled
        INFINITE);    // indefinite wait

    switch (dwWaitResult)
    {
        // All read-event objects were signaled.
        case WAIT_OBJECT_0:
            // Write to the shared buffer.
            break;

        // An error occurred.
        default:
            printf("Wait error: %d\n", GetLastError());
            ExitProcess(0);
    }

    // Set hGlobalWriteEvent to signaled.

    if (! SetEvent(hGlobalWriteEvent) )
    {
        // Error exit.
    }

    // Set all read events to signaled.
    for(i = 1; i <= NUMTHREADS; i++)
        if (! SetEvent(hReadEvents[i]) ) {
            // Error exit.
        }
}

Before starting a read operation, each reader thread uses WaitForMultipleObjects to wait for the application-defined global variable hGlobalWriteEvent and its own read event to be signaled. When WaitForMultipleObjects returns, the reader thread's auto-reset event has been reset to nonsignaled. This blocks the master thread from writing to the buffer until the reader thread uses the SetEvent function to set the event's state back to signaled.

VOID ThreadFunction(LPVOID lpParam)
{
    DWORD dwWaitResult;
    HANDLE hEvents[2];

    hEvents[0] = *(HANDLE*)lpParam;  // thread's read event
    hEvents[1] = hGlobalWriteEvent;

    dwWaitResult = WaitForMultipleObjects(
        2,            // number of handles in array
        hEvents,      // array of event handles
        TRUE,         // wait till all are signaled
        INFINITE);    // indefinite wait

    switch (dwWaitResult)
    {

        // Both event objects were signaled.
        case WAIT_OBJECT_0:
            // Read from the shared buffer.
            break;

        // An error occurred.
        default:
            printf("Wait error: %d\n", GetLastError());
            ExitThread(0);
    }

    // Set the read event to signaled.

    if (! SetEvent(hEvents[0]) )
    {
        // Error exit.
    }
}


Using Critical Section Objects

The following example shows how a thread initializes, enters, and leaves a critical section. As with the mutex example (see Using Mutex Objects), this example uses structured exception-handling syntax to ensure that the thread calls the LeaveCriticalSection function to release its ownership of the critical section object.

CRITICAL_SECTION CriticalSection;

// Initialize the critical section.
InitializeCriticalSection(&CriticalSection);

// Request ownership of the critical section.
__try
{
    EnterCriticalSection(&CriticalSection);

    // Access the shared resource.
}
__finally
{
    // Release ownership of the critical section.
    LeaveCriticalSection(&CriticalSection);

    // Release resources used by the critical section object.
    DeleteCriticalSection(&CriticalSection)
}


Using Timer Queues

The following example creates a timer routine that will be executed by a timer-queue thread after a 10 second delay. First, the code uses the CreateEvent function to create an event object that is signaled when the timer-queue thread completes. Then it creates a timer queue and a timer-queue timer, using the CreateTimerQueue and CreateTimerQueueTimer functions, respectively. The code uses the WaitForSingleObject function to determine when the timer routine has completed. Finally, the code calls DeleteTimerQueue to clean up.

For more information on the timer routine, see WaitOrTimerCallback.

#include <windows.h>
#include <stdio.h>

HANDLE gDoneEvent;

VOID CALLBACK TimerRoutine(PVOID lpParam, BOOL TimerOrWaitFired)
{
    if (lpParam == NULL)
    {
        printf("TimerRoutine lpParam is NULL\n");
    }
    else
    {
        // lpParam points to the argument; in this case it is an int

        printf("Timer routine called. Parameter is %d.\n",
                *(int*)lpParam);
    }

    SetEvent(gDoneEvent);
}

int main()
{
    HANDLE hTimer = NULL;
    HANDLE hTimerQueue = NULL;
    int arg = 123;

    // Use an event object to track the TimerRoutine execution
    gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!gDoneEvent)
    {
        printf("CreateEvent failed (%d)\n", GetLastError());
        return 1;
    }

    // Create the timer queue.
    hTimerQueue = CreateTimerQueue();
    if (!hTimerQueue)
    {
        printf("CreateTimerQueue failed (%d)\n", GetLastError());
        return 2;
    }

    // Set a timer to call the timer routine in 10 seconds.
    if (!CreateTimerQueueTimer(
        &hTimer, hTimerQueue, TimerRoutine, &arg , 10000, 0, 0))
    {
        printf("CreateTimerQueueTimer failed (%d)\n", GetLastError());
        return 3;
    }

    // Do other useful work here

    printf("Call timer routine in 10 seconds...\n");

    // Wait for the timer-queue thread to complete using an event
    // object. The thread will signal the event at that time.

    if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
        printf("WaitForSingleObject failed (%d)\n", GetLastError());

    // Delete all timers in the timer queue.
    if (!DeleteTimerQueue(hTimerQueue))
        printf("DeleteTimerQueue failed (%d)\n", GetLastError());

    return 0;
}


Using Waitable Timer Objects

The following example creates a timer that will be signaled after a 10 second delay. First, the code uses the CreateWaitableTimer function to create a waitable timer object. Then it uses the SetWaitableTimer function to set the timer. The code uses the WaitForSingleObject function to determine when the timer has been signaled.

#include <windows.h>
#include <stdio.h>

int main()
{
    HANDLE hTimer = NULL;
    LARGE_INTEGER liDueTime;

    liDueTime.QuadPart=-100000000;

    // Create a waitable timer.
    hTimer = CreateWaitableTimer(NULL, TRUE, "WaitableTimer");
    if (!hTimer)
    {
        printf("CreateWaitableTimer failed (%d)\n", GetLastError());
        return 1;
    }

    printf("Waiting for 10 seconds...\n");

    // Set a timer to wait for 10 seconds.
    if (!SetWaitableTimer(
        hTimer, &liDueTime, 0, NULL, NULL, 0))
    {
        printf("SetWaitableTimer failed (%d)\n", GetLastError());
        return 2;
    }

    // Wait for the timer.

    if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
        printf("WaitForSingleObject failed (%d)\n", GetLastError());
    else printf("Timer was signaled.\n");

    return 0;
}


Synchronization Reference

The following elements are used with synchronization.

  • Synchronization Functions
  • Synchronization Structures
  • Synchronization Macros


Synchronization Functions

The following functions are used in synchronization.

Asynchronous Function | Description
APCProc | An application-defined callback function used with the QueueUserAPC function.
GetOverlappedResult | Retrieves the results of an overlapped operation.
QueueUserAPC | Adds a user-mode asynchronous procedure call (APC) object to the APC queue of the specified thread.

Critical-Section Function | Description
DeleteCriticalSection | Releases all resources used by an unowned critical section object.
EnterCriticalSection | Waits for ownership of the specified critical section object.
InitializeCriticalSection | Initializes a critical section object.
InitializeCriticalSectionAndSpinCount | Initializes a critical section object and sets the spin count for the critical section.
LeaveCriticalSection | Releases ownership of the specified critical section object.
SetCriticalSectionSpinCount | Sets the spin count for the specified critical section.
TryEnterCriticalSection | Attempts to enter a critical section without blocking.

Event Function | Description
CreateEvent | Creates or opens a named or unnamed event object.
OpenEvent | Opens an existing named event object.
PulseEvent | Sets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads.
ResetEvent | Sets the specified event object to the nonsignaled state.
SetEvent | Sets the specified event object to the signaled state.

Interlocked Function | Description
InterlockedCompareExchange | Performs an atomic comparison of the specified values and exchanges the values, based on the outcome of the comparison.
InterlockedCompareExchangePointer | Performs an atomic comparison of the specified values and exchange of the values, based on the outcome of the comparison.
InterlockedDecrement | Decrements (decreases by one) the value of the specified variable and checks the resulting value.
InterlockedExchange | Atomically exchanges a pair of values.
InterlockedExchangeAdd | Performs an atomic addition of an increment value to an addend variable.
InterlockedExchangePointer | Atomically exchanges a pair of values.
InterlockedIncrement | Increments (increases by one) the value of the specified variable and checks the resulting value.

Mutex Function | Description
CreateMutex | Creates or opens a named or unnamed mutex object.
OpenMutex | Opens an existing named mutex object.
ReleaseMutex | Releases ownership of the specified mutex object.

Semaphore Function | Description
CreateSemaphore | Creates or opens a named or unnamed semaphore object.
OpenSemaphore | Opens an existing named semaphore object.
ReleaseSemaphore | Increases the count of the specified semaphore object by a specified amount.

Timer-Queue Timer Function | Description
ChangeTimerQueueTimer | Updates a timer-queue timer.
CreateTimerQueue | Creates a queue for timers.
CreateTimerQueueTimer | Creates a timer-queue timer.
DeleteTimerQueue | Deletes a timer queue.
DeleteTimerQueueEx | Deletes a timer queue.
DeleteTimerQueueTimer | Cancels a timer-queue timer.

Wait Function | Description
MsgWaitForMultipleObjects | Returns when the specified criteria for the specified objects is met.
MsgWaitForMultipleObjectsEx | Returns when the specified criteria for the specified objects is met.
RegisterWaitForSingleObject | Directs a wait thread in the thread pool to wait on the object.
SignalObjectAndWait | Allows the caller to atomically signal an object and wait on another object.
UnregisterWait | Cancels a registered wait operation.
UnregisterWaitEx | Cancels a registered wait operation.
WaitForMultipleObjects | Returns when the specified criteria for the specified objects is met.
WaitForMultipleObjectsEx | Returns when the specified criteria for the specified objects is met.
WaitForSingleObject | Returns when the specified criteria for the specified object is met.
WaitForSingleObjectEx | Returns when the specified criteria for the specified object is met.
WaitOrTimerCallback | Returns when the specified criteria is met.

Waitable Timer Function | Description
CancelWaitableTimer | Sets the specified waitable timer to the inactive state.
CreateWaitableTimer | Creates or opens a waitable timer object.
OpenWaitableTimer | Opens an existing named waitable timer object.
SetWaitableTimer | Activates the specified waitable timer.
TimerAPCProc | Application-defined timer completion routine used with the SetWaitableTimer function.


APCProc

The APCProc function is an application-defined completion routine. Specify this address when calling the QueueUserAPC function. The PAPCFUNC type defines a pointer to this callback function. APCProc is a placeholder for the application-defined function name.

VOID CALLBACK APCProc(
  ULONG_PTR dwParam
);

Parameters

dwParam
[in] Receives the data passed to the function using the dwData parameter of the QueueUserAPC function.

Return Value

This function does not return a value.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Synchronization Overview, Synchronization Functions, QueueUserAPC


CancelWaitableTimer

The CancelWaitableTimer function sets the specified waitable timer to the inactive state.

BOOL CancelWaitableTimer(
  HANDLE hTimer  // handle to timer
);

Parameters

hTimer
[in] Handle to the timer object. The CreateWaitableTimer or OpenWaitableTimer function returns this handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The CancelWaitableTimer function does not change the signaled state of the timer. It stops the timer before it can be set to the signaled state and cancels outstanding APCs. Therefore, threads performing a wait operation on the timer remain waiting until they time out or the timer is reactivated and its state is set to signaled. If the timer is already in the signaled state, it remains in that state.

To reactivate the timer, call the SetWaitableTimer function.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateWaitableTimer, OpenWaitableTimer, SetWaitableTimer


ChangeTimerQueueTimer

The ChangeTimerQueueTimer function updates a timer-queue timer that was created by the CreateTimerQueueTimer function.

BOOL ChangeTimerQueueTimer(
  HANDLE TimerQueue,  // handle to timer queue
  HANDLE Timer,       // handle to timer
  ULONG DueTime,      // timer due time
  ULONG Period        // timer period
);

Parameters

TimerQueue
[in] Handle to a timer queue. This handle is returned by the CreateTimerQueue function.

If this parameter is NULL, the timer is associated with the default timer queue.

Timer
[in] Handle to a timer-queue timer. This handle is returned by the CreateTimerQueueTimer function.
DueTime
[in] Specifies the time, in milliseconds, after which the timer should expire.
Period
[in] Specifies the period of the timer, in milliseconds. If Period is zero, the timer is signaled once. If Period is greater than zero, the timer is periodic. A periodic timer automatically reactivates each time the period elapses, until the timer is canceled using the DeleteTimerQueueTimer function or reset using ChangeTimerQueueTimer.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

You can call ChangeTimerQueueTimer in a timer callback.

If you call ChangeTimerQueueTimer on a one-shot timer (its period is zero) that has already expired, the timer is not updated.

Do not call ChangeTimerQueueTimer after calling DeleteTimerQueueTimer on a handle.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueue, CreateTimerQueueTimer, DeleteTimerQueueTimer, Thread Pooling


CreateEvent

The CreateEvent function creates or opens a named or unnamed event object.

HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes, // SD
  BOOL bManualReset,                       // reset type
  BOOL bInitialState,                      // initial state
  LPCTSTR lpName                           // object name
);

Parameters

lpEventAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpEventAttributes is NULL, the handle cannot be inherited.

Windows NT/2000 or later: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new event. If lpEventAttributes is NULL, the event gets a default security descriptor.

bManualReset
[in] Specifies whether a manual-reset or auto-reset event object is created. If TRUE, then you must use the ResetEvent function to manually reset the state to nonsignaled. If FALSE, the system automatically resets the state to nonsignaled after a single waiting thread has been released.
bInitialState
[in] Specifies the initial state of the event object. If TRUE, the initial state is signaled; otherwise, it is nonsignaled.
lpName
[in] Pointer to a null-terminated string specifying the name of the event object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.

If lpName matches the name of an existing named event object, this function requests EVENT_ALL_ACCESS access to the existing object. In this case, the bManualReset and bInitialState parameters are ignored because they have already been set by the creating process. If the lpEventAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the event object is created without a name.

If lpName matches the name of an existing semaphore, mutex, waitable timer, job, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the event object. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateEvent has EVENT_ALL_ACCESS access to the new event object and can be used in any function that requires a handle to an event object.

Any thread of the calling process can specify the event-object handle in a call to one of the wait functions. The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The initial state of the event object is specified by the bInitialState parameter. Use the SetEvent function to set the state of an event object to signaled. Use the ResetEvent function to reset the state of an event object to nonsignaled.

When the state of a manual-reset event object is signaled, it remains signaled until it is explicitly reset to nonsignaled by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object, can be released while the object's state is signaled.

When the state of an auto-reset event object is signaled, it remains signaled until a single waiting thread is released; the system then automatically resets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.

Multiple processes can have handles of the same event object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

  • A child process created by the CreateProcess function can inherit a handle to an event object if the lpEventAttributes parameter of CreateEvent enabled inheritance.
  • A process can specify the event-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.
  • A process can specify the name of an event object in a call to the OpenEvent or CreateEvent function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The event object is destroyed when its last handle has been closed.

For an example that uses CreateEvent, see Using Event Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CloseHandle, CreateProcess, DuplicateHandle, OpenEvent, ResetEvent, SECURITY_ATTRIBUTES, SetEvent, Object Names


CreateMutex

The CreateMutex function creates or opens a named or unnamed mutex object.

HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,  // SD
  BOOL bInitialOwner,                       // initial owner
  LPCTSTR lpName                            // object name
);

Parameters

lpMutexAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpMutexAttributes is NULL, the handle cannot be inherited.

Windows NT/2000 or later: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new mutex. If lpMutexAttributes is NULL, the mutex gets a default security descriptor.

bInitialOwner
[in] Specifies the initial owner of the mutex object. If this value is TRUE and the caller created the mutex, the calling thread obtains ownership of the mutex object. Otherwise, the calling thread does not obtain ownership of the mutex. To determine if the caller created the mutex, see the Return Values section.
lpName
[in] Pointer to a null-terminated string specifying the name of the mutex object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.

If lpName matches the name of an existing named mutex object, this function requests MUTEX_ALL_ACCESS access to the existing object. In this case, the bInitialOwner parameter is ignored because it has already been set by the creating process. If the lpMutexAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the mutex object is created without a name.

If lpName matches the name of an existing event, semaphore, waitable timer, job, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the mutex object. If the named mutex object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. Otherwise, the caller created the mutex.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateMutex has MUTEX_ALL_ACCESS access to the new mutex object and can be used in any function that requires a handle to a mutex object.

Any thread of the calling process can specify the mutex-object handle in a call to one of the wait functions. The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The state of a mutex object is signaled when it is not owned by any thread. The creating thread can use the bInitialOwner flag to request immediate ownership of the mutex. Otherwise, a thread must use one of the wait functions to request ownership. When the mutex's state is signaled, one waiting thread is granted ownership, the mutex's state changes to nonsignaled, and the wait function returns. Only one thread can own a mutex at any given time. The owning thread uses the ReleaseMutex function to release its ownership.

The thread that owns a mutex can specify the same mutex in repeated wait function calls without blocking its execution. Typically, you would not wait repeatedly for the same mutex, but this mechanism prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.

Two or more processes can call CreateMutex to create the same named mutex. The first process actually creates the mutex, and subsequent processes open a handle to the existing mutex. This enables multiple processes to get handles of the same mutex, while relieving the user of the responsibility of ensuring that the creating process is started first. When using this technique, you should set the bInitialOwner flag to FALSE; otherwise, it can be difficult to be certain which process has initial ownership.

Multiple processes can have handles of the same mutex object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

  • A child process created by the CreateProcess function can inherit a handle to a mutex object if the lpMutexAttributes parameter of CreateMutex enabled inheritance.
  • A process can specify the mutex-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.
  • A process can specify the name of a mutex object in a call to the OpenMutex or CreateMutex function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.

For an example that uses CreateMutex, see Using Mutex Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CloseHandle, CreateProcess, DuplicateHandle, OpenMutex, ReleaseMutex, SECURITY_ATTRIBUTES, Object Names


CreateSemaphore

The CreateSemaphore function creates or opens a named or unnamed semaphore object.

HANDLE CreateSemaphore(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // SD
  LONG lInitialCount,                          // initial count
  LONG lMaximumCount,                          // maximum count
  LPCTSTR lpName                               // object name
);

Parameters

lpSemaphoreAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes. If lpSemaphoreAttributes is NULL, the handle cannot be inherited.

Windows NT/2000 or later: The lpSecurityDescriptor member of the structure specifies a security descriptor for the new semaphore. If lpSemaphoreAttributes is NULL, the semaphore gets a default security descriptor.

lInitialCount
[in] Specifies an initial count for the semaphore object. This value must be greater than or equal to zero and less than or equal to lMaximumCount. The state of a semaphore is signaled when its count is greater than zero and nonsignaled when it is zero. The count is decreased by one whenever a wait function releases a thread that was waiting for the semaphore. The count is increased by a specified amount by calling the ReleaseSemaphore function.
lMaximumCount
[in] Specifies the maximum count for the semaphore object. This value must be greater than zero.
lpName
[in] Pointer to a null-terminated string specifying the name of the semaphore object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.

If lpName matches the name of an existing named semaphore object, this function requests SEMAPHORE_ALL_ACCESS access to the existing object. In this case, the lInitialCount and lMaximumCount parameters are ignored because they have already been set by the creating process. If the lpSemaphoreAttributes parameter is not NULL, it determines whether the handle can be inherited, but its security-descriptor member is ignored.

If lpName is NULL, the semaphore object is created without a name.

If lpName matches the name of an existing event, mutex, waitable timer, job, or file-mapping object, the function fails and the GetLastError function returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the semaphore object. If the named semaphore object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateSemaphore has SEMAPHORE_ALL_ACCESS access to the new semaphore object and can be used in any function that requires a handle to a semaphore object.

Any thread of the calling process can specify the semaphore-object handle in a call to one of the wait functions. The single-object wait functions return when the state of the specified object is signaled. The multiple-object wait functions can be instructed to return either when any one or when all of the specified objects are signaled. When a wait function returns, the waiting thread is released to continue its execution.

The state of a semaphore object is signaled when its count is greater than zero, and nonsignaled when its count is equal to zero. The lInitialCount parameter specifies the initial count. Each time a waiting thread is released because of the semaphore's signaled state, the count of the semaphore is decreased by one. Use the ReleaseSemaphore function to increment a semaphore's count by a specified amount. The count can never be less than zero or greater than the value specified in the lMaximumCount parameter.

Multiple processes can have handles of the same semaphore object, enabling use of the object for interprocess synchronization. The following object-sharing mechanisms are available:

  • A child process created by the CreateProcess function can inherit a handle to a semaphore object if the lpSemaphoreAttributes parameter of CreateSemaphore enabled inheritance.
  • A process can specify the semaphore-object handle in a call to the DuplicateHandle function to create a duplicate handle that can be used by another process.
  • A process can specify the name of a semaphore object in a call to the OpenSemaphore or CreateSemaphore function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed.

For an example that uses CreateSemaphore, see Using Semaphore Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CloseHandle, CreateProcess, DuplicateHandle, OpenSemaphore, ReleaseSemaphore, SECURITY_ATTRIBUTES, Object Names


CreateTimerQueue

The CreateTimerQueue function creates a queue for timers. Timer-queue timers are lightweight objects that enable you to specify a callback function to be called at a specified time.

HANDLE CreateTimerQueue(VOID);

Parameters

This function has no parameters.

Return Values

If the function succeeds, the return value is a handle to the timer queue. This handle can be used only in functions that require a handle to a timer queue.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

To add a timer to the queue, call the CreateTimerQueueTimer function. To remove a timer from the queue, call the DeleteTimerQueueTimer function.

When you are finished with the queue of timers, call the DeleteTimerQueueEx function to delete the timer queue. Any pending timers in the queue are canceled and deleted.

Example

For an example that uses CreateTimerQueue, see Using Timer Queues.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueueTimer, DeleteTimerQueueEx, DeleteTimerQueueTimer, Thread Pooling


CreateTimerQueueTimer

The CreateTimerQueueTimer function creates a timer-queue timer. This timer expires at the specified due time, then after every specified period. When the timer expires, the callback function is called.

BOOL CreateTimerQueueTimer(
  PHANDLE phNewTimer,           // handle to timer
  HANDLE TimerQueue,            // handle to timer queue
  WAITORTIMERCALLBACK Callback, // timer callback function
  PVOID Parameter,              // callback parameter
  DWORD DueTime,                // timer due time
  DWORD Period,                 // timer period
  ULONG Flags                   // options
);

Parameters

phNewTimer
[out] Pointer to a buffer that receives a handle to the timer-queue timer on return.
TimerQueue
[in] Handle to a timer queue. This handle is returned by the CreateTimerQueue function.

If this parameter is NULL, the timer is associated with the default timer queue.

Callback
[in] Pointer to the application-defined function of type WAITORTIMERCALLBACK to be executed when the timer expires. For more information, see WaitOrTimerCallback.
Parameter
[in] Specifies a single parameter value that will be passed to the callback function.
DueTime
[in] Specifies the amount of time, in milliseconds, to elapse before the timer is to be set to the signaled state for the first time.
Period
[in] Specifies the period of the timer, in milliseconds. If this parameter is zero, the timer is signaled once. If this parameter is greater than zero, the timer is periodic. A periodic timer automatically reactivates each time the period elapses, until the timer is canceled.
Flags
[in] This parameter can be one or more of the following values.
Value | Meaning
WT_EXECUTEINTIMERTHREAD | The callback function is invoked by the timer thread itself. This flag should be used only for short tasks or it could affect other timer operations.
WT_EXECUTEINIOTHREAD The callback function is queued to an I/O worker thread. This flag should be used if the function should be executed in a thread that waits in an alertable state.

The callback function is queued as an APC. Be sure to address reentrancy issues if the function performs an alertable wait operation.

WT_EXECUTEINPERSISTENTTHREAD The callback function is queued to a thread that never terminates. This flag should be used only for short tasks or it could affect other timer operations.

Note that currently no worker thread is persistent, although no worker thread will terminate if there are any pending I/O requests.
WT_EXECUTELONGFUNCTION | Specifies that the callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.
WT_EXECUTEONLYONCE | The timer will be set to the signaled state only once.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

If the DueTime and Period parameters are both nonzero, the timer will be signaled first at the due time, then periodically. The callback is called every time the period elapses, whether or not the previous callback has finished executing.

To cancel a timer, call the DeleteTimerQueueTimer function. To cancel all timers in a timer queue, call the DeleteTimerQueueEx function.

Example

For an example that uses CreateTimerQueueTimer, see Using Timer Queues.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueue, DeleteTimerQueueEx, DeleteTimerQueueTimer, Thread Pooling


CreateWaitableTimer

The CreateWaitableTimer function creates or opens a waitable timer object.

HANDLE CreateWaitableTimer(
  LPSECURITY_ATTRIBUTES lpTimerAttributes, // SD
  BOOL bManualReset,                       // reset type
  LPCTSTR lpTimerName                      // object name
);

Parameters

lpTimerAttributes
[in] Pointer to a SECURITY_ATTRIBUTES structure that specifies a security descriptor for the new timer object and determines whether child processes can inherit the returned handle. If lpTimerAttributes is NULL, the timer object gets a default security descriptor and the handle cannot be inherited.
bManualReset
[in] Specifies the timer type. If bManualReset is TRUE, the timer is a manual-reset notification timer. Otherwise, the timer is a synchronization timer.
lpTimerName
[in] Pointer to a null-terminated string specifying the name of the timer object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.

If the string specified in the lpTimerName parameter matches the name of an existing named timer object, the call returns successfully and the GetLastError function returns ERROR_ALREADY_EXISTS.

If lpTimerName is NULL, the timer object is created without a name.

If lpTimerName matches the name of an existing event, semaphore, mutex, job, or file-mapping object, the function fails and GetLastError returns ERROR_INVALID_HANDLE. This occurs because these objects share the same name space.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly create the object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the timer object. If the named timer object exists before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The handle returned by CreateWaitableTimer is created with the TIMER_ALL_ACCESS access right. This handle can be used in any function that requires a handle to a timer object.

Any thread of the calling process can specify the timer object handle in a call to one of the wait functions.

Multiple processes can have handles to the same timer object, enabling use of the object for interprocess synchronization.

  • A process created by the CreateProcess function can inherit a handle to a timer object if the lpTimerAttributes parameter of CreateWaitableTimer enables inheritance.
  • A process can specify the timer object handle in a call to the DuplicateHandle function. The resulting handle can be used by another process.
  • A process can specify the name of a timer object in a call to the OpenWaitableTimer or CreateWaitableTimer function.

Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The timer object is destroyed when its last handle has been closed.

Example

For an example that uses CreateWaitableTimer, see Using Waitable Timer Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CancelWaitableTimer, CloseHandle, CreateProcess, DuplicateHandle, FILETIME, OpenWaitableTimer, SECURITY_ATTRIBUTES, SetWaitableTimer, Object Names


DeleteCriticalSection

The DeleteCriticalSection function releases all resources used by an unowned critical section object.

VOID DeleteCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection   // critical section
);

Parameters

lpCriticalSection
[in/out] Pointer to the critical section object.

Return Values

This function does not return a value.

Remarks

Deleting a critical section object releases all system resources used by the object. After a critical section object has been deleted, it cannot be specified in the EnterCriticalSection, TryEnterCriticalSection, or LeaveCriticalSection function.

If a critical section is deleted while it is still owned, the state of the threads waiting for ownership of the deleted critical section is undefined.

For an example that uses DeleteCriticalSection, see Using Critical Section Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection TryEnterCriticalSection


DeleteTimerQueue

The DeleteTimerQueue function deletes a timer queue. Any pending timers in the queue are canceled and deleted.

To use a completion event, call the DeleteTimerQueueEx function.

BOOL DeleteTimerQueue(
  HANDLE TimerQueue,      // handle to timer queue
);

Parameters

TimerQueue
[in] Handle to a timer queue. This handle is returned by the CreateTimerQueue function.

If the timer was created using the default timer queue, this parameter should be NULL.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

DeleteTimerQueue does not wait for all callback functions associated with the timer to complete.

Example

For an example that uses DeleteTimerQueue, see Using Timer Queues.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueue, DeleteTimerQueueEx, DeleteTimerQueueTimer, Thread Pooling


DeleteTimerQueueEx

The DeleteTimerQueueEx function deletes a timer queue. Any pending timers in the queue are canceled and deleted.

BOOL DeleteTimerQueueEx(
  HANDLE TimerQueue,      // handle to timer queue
  HANDLE CompletionEvent  // handle to completion event
);

Parameters

TimerQueue
[in] Handle to a timer queue. This handle is returned by the CreateTimerQueue function.

If the timer was created using the default timer queue, this parameter should be NULL.

CompletionEvent
[in] Specifies an optional event to be signaled when the function is successful and all callback functions have completed. This parameter can be NULL.

If this parameter is INVALID_HANDLE_VALUE, the function waits for all callback functions to complete before returning. Otherwise, the function returns immediately.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Do not make blocking calls to DeleteTimerQueueEx from within a timer callback.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueue, DeleteTimerQueueTimer, Thread Pooling


DeleteTimerQueueTimer

The DeleteTimerQueueTimer function cancels a timer-queue timer.

BOOL DeleteTimerQueueTimer(
  HANDLE TimerQueue,      // handle to timer queue
  HANDLE Timer,           // handle to timer
  HANDLE CompletionEvent  // handle to completion event
);

Parameters

TimerQueue
[in] Handle to a timer queue. This handle is returned by the CreateTimerQueue function.

If the timer was created using the default timer queue, this parameter should be NULL.

Timer
[in] Handle to a timer-queue timer. This handle is returned by the CreateTimerQueueTimer function.
CompletionEvent
[in] Specifies an optional event to be signaled when the function is successful and all callback functions have completed. This parameter can be NULL.

If this parameter is INVALID_HANDLE_VALUE, the function waits for all callback functions to complete before returning. Otherwise, the function returns immediately.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

You can set CompletionEvent to INVALID_HANDLE_VALUE when calling this function from within the timer callback of another timer as long as the callback function is not executed in the timer thread. However, a deadlock may occur if two callback functions attempt a blocking DeleteTimerQueueTimer call on each others' timers. Furthermore, you cannot making a blocking deletion call on a timer associated with the callback.

To cancel all timers in a timer queue, call the DeleteTimerQueueEx function.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueue, CreateTimerQueueTimer, DeleteTimerQueueEx, Thread Pooling


EnterCriticalSection

The EnterCriticalSection function waits for ownership of the specified critical section object. The function returns when the calling thread is granted ownership.

VOID EnterCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection  // critical section
);

Parameters

lpCriticalSection
[in/out] Pointer to the critical section object.

Return Values

This function does not return a value.

In low memory situations, EnterCriticalSection can raise a STATUS_INVALID_HANDLE exception. To avoid problems, use structured exception handling, or call the InitializeCriticalSectionAndSpinCount function to preallocate the event used by EnterCriticalSection instead of calling the InitializeCriticalSection function, which forces EnterCriticalSection to allocate the event.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call InitializeCriticalSection or InitializeCriticalSectionAndSpinCount to initialize the object.

To enable mutually exclusive access to a shared resource, each thread calls the EnterCriticalSection or TryEnterCriticalSection function to request ownership of the critical section before executing any section of code that accesses the protected resource. The difference is that TryEnterCriticalSection returns immediately, regardless of whether it obtained ownership of the critical section, while EnterCriticalSection blocks until the thread can take ownership of the critical section. When it has finished executing the protected code, the thread uses the LeaveCriticalSection function to relinquish ownership, enabling another thread to become owner and access the protected resource. The thread must call LeaveCriticalSection once for each time that it entered the critical section. The thread enters the critical section each time EnterCriticalSection and TryEnterCriticalSection succeed.

After a thread has ownership of a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blocking its execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns.

Any thread of the process can use the DeleteCriticalSection function to release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.

If a thread terminates while it has ownership of a critical section, the state of the critical section is undefined.

If a critical section is deleted while it is still owned, the state of the threads waiting for ownership of the deleted critical section is undefined.

For an example that uses EnterCriticalSection, see Using Critical Section Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, DeleteCriticalSection, InitializeCriticalSection, InitializeCriticalSectionAndSpinCount, LeaveCriticalSection TryEnterCriticalSection


GetOverlappedResult

The GetOverlappedResult function retrieves the results of an overlapped operation on the specified file, named pipe, or communications device.

Windows 95/98/Me: This function works only on communications devices or on files opened by using the DeviceIoControl function.

BOOL GetOverlappedResult(
  HANDLE hFile,                       // handle to file, pipe, or device
  LPOVERLAPPED lpOverlapped,          // overlapped structure
  LPDWORD lpNumberOfBytesTransferred, // bytes transferred
  BOOL bWait                          // wait option
);

Parameters

hFile
[in] Handle to the file, named pipe, or communications device. This is the same handle that was specified when the overlapped operation was started by a call to the ReadFile, WriteFile, ConnectNamedPipe, TransactNamedPipe, DeviceIoControl, or WaitCommEvent function.
lpOverlapped
[in] Pointer to an OVERLAPPED structure that was specified when the overlapped operation was started.
lpNumberOfBytesTransferred
[out] Pointer to a variable that receives the number of bytes that were actually transferred by a read or write operation. For a TransactNamedPipe operation, this is the number of bytes that were read from the pipe. For a DeviceIoControl operation, this is the number of bytes of output data returned by the device driver. For a ConnectNamedPipe or WaitCommEvent operation, this value is undefined.
bWait
[in] Specifies whether the function should wait for the pending overlapped operation to be completed. If TRUE, the function does not return until the operation has been completed. If FALSE and the operation is still pending, the function returns FALSE and the GetLastError function returns ERROR_IO_INCOMPLETE.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The results reported by the GetOverlappedResult function are those of the specified handle's last overlapped operation to which the specified OVERLAPPED structure was provided, and for which the operation's results were pending. A pending operation is indicated when the function that started the operation returns FALSE, and the GetLastError function returns ERROR_IO_PENDING. When an I/O operation is pending, the function that started the operation resets the hEvent member of the OVERLAPPED structure to the nonsignaled state. Then when the pending operation has been completed, the system sets the event object to the signaled state.

Specify a manual-reset event object in the OVERLAPPED structure. If an auto-reset event object is used, the event handle must not be specified in any other wait operation in the interval between starting the overlapped operation and the call to GetOverlappedResult. For example, the event object is sometimes specified in one of the wait functions to wait for the operation's completion. When the wait function returns, the system sets an auto-reset event's state to nonsignaled, and a subsequent call to GetOverlappedResult with the bWait parameter set to TRUE causes the function to be blocked indefinitely.

If the bWait parameter is TRUE, GetOverlappedResult determines whether the pending operation has been completed by waiting for the event object to be in the signaled state.

Windows 95/98/Me: If bWait is TRUE, the hEvent member of the OVERLAPPED structure must not be NULL.

Windows NT/2000 or later: If the hEvent member of the OVERLAPPED structure is NULL, the system uses the state of the hFile handle to signal when the operation has been completed. Use of file, named pipe, or communications-device handles for this purpose is discouraged. It is safer to use an event object because of the confusion that can occur when multiple simultaneous overlapped operations are performed on the same file, named pipe, or communications device. In this situation, there is no way to know which operation caused the object's state to be signaled.

For an example that uses GetOverlappedResult, see Testing for the End of the File.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CancelIo, ConnectNamedPipe, CreateEvent, DeviceIoControl, GetLastError, OVERLAPPED, ReadFile, TransactNamedPipe, WaitCommEvent, WriteFile


InitializeCriticalSection

The InitializeCriticalSection function initializes a critical section object.

VOID InitializeCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection  // critical section
);

Parameters

lpCriticalSection
[out] Pointer to the critical section object.

Return Values

This function does not return a value.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. There is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads.

The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function to initialize the object.

After a critical section object has been initialized, the threads of the process can specify the object in the EnterCriticalSection, TryEnterCriticalSection, or LeaveCriticalSection function to provide mutually exclusive access to a shared resource. For similar synchronization between the threads of different processes, use a mutex object.

A critical section object cannot be moved or copied. The process must also not modify the object, but must treat it as logically opaque. Use only the critical section functions to manage critical section objects.

For an example that uses InitializeCriticalSection, see Using Critical Section Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateMutex, DeleteCriticalSection, EnterCriticalSection, InitializeCriticalSectionAndSpinCount, LeaveCriticalSection, TryEnterCriticalSection


InitializeCriticalSectionAndSpinCount

The InitializeCriticalSectionAndSpinCount function initializes a critical section object and sets the spin count for the critical section.

BOOL InitializeCriticalSectionAndSpinCount(
  LPCRITICAL_SECTION lpCriticalSection,  // critical section
  DWORD dwSpinCount                      // spin count
);

Parameters

lpCriticalSection
[in/out] Pointer to the critical section object.
dwSpinCount
[in] Specifies the spin count for the critical section object. On single-processor systems, the spin count is ignored and the critical section spin count is set to 0. On multiprocessor systems, if the critical section is unavailable, the calling thread will spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation.

Windows 2000 or later: If the high-order bit is set, the function preallocates the event used by the EnterCriticalSection function. Do not set this bit if you are creating a large number of critical section objects, because it will consume a significant amount of nonpaged pool.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. There is no guarantee about the order in which threads will obtain ownership of the critical section, however, the system will be fair to all threads.

The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function to initialize the object. You can subsequently modify the spin count by calling the SetCriticalSectionSpinCount function.

After a critical section object has been initialized, the threads of the process can specify the object in the EnterCriticalSection, TryEnterCriticalSection, or LeaveCriticalSection function to provide mutually exclusive access to a shared resource. For similar synchronization between the threads of different processes, use a mutex object.

A critical section object cannot be moved or copied. The process must also not modify the object, but must treat it as logically opaque. Use only the critical section functions to manage critical section objects.

The spin count is useful for critical sections of short duration that can experience high levels of contention. Consider a worst-case scenario, in which an application on an SMP system has two or three threads constantly allocating and releasing memory from the heap. The application serializes the heap with a critical section. In the worst-case scenario, contention for the critical section is constant, and each thread makes an expensive call to the WaitForSingleObject function. However, if the spin count is set properly, the calling thread will not immediately call WaitForSingleObject when contention occurs. Instead, the calling thread can acquire ownership of the critical section if it is released during the spin operation.

You can improve performance significantly by choosing a small spin count for a critical section of short duration. The heap manager uses a spin count of roughly 4000 for its per-heap critical sections. This gives great performance and scalability in almost all worst-case scenarios.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 SP3 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, InitializeCriticalSection, SetCriticalSectionSpinCount, WaitForSingleObject


InterlockedCompareExchange

The InterlockedCompareExchange function performs an atomic comparison of the specified values and exchanges the values, based on the outcome of the comparison. The function prevents more than one thread from using the same variable simultaneously.

If you are exchanging pointer values, this function has been superseded by the InterlockedCompareExchangePointer function.

LONG InterlockedCompareExchange(
  LPLONG Destination,  // destination address
  LONG Exchange,       // exchange value
  LONG Comperand       // value to compare
);

Parameters

Destination
[in/out] Specifies the address of the destination value. The sign is ignored.
Exchange
[in] Specifies the exchange value. The sign is ignored.
Comperand
[in] Specifies the value to compare to Destination. The sign is ignored.

Return Values

The return value is the initial value of the destination.

Remarks

The functions InterlockedCompareExchange, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd, and InterlockedIncrement provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The InterlockedCompareExchange function performs an atomic comparison of the Destination value with the Comperand value. If the Destination value is equal to the Comperand value, the Exchange value is stored in the address specified by Destination. Otherwise, no operation is performed.

The variables for InterlockedCompareExchange must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems and any non-x86 systems.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchangePointer, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd, InterlockedIncrement


InterlockedCompareExchangePointer

The InterlockedCompareExchangePointer function performs an atomic comparison of the specified values parameters and exchanges the values, based on the outcome of the comparison. More than one thread cannot use the same variable simultaneously.

If you are exchanging pointer values, this function supersedes the InterlockedCompareExchange function.

PVOID InterlockedCompareExchangePointer (
  PVOID *Destination,  // destination address
  PVOID Exchange,      // exchange value
  PVOID Comperand      // value to compare
);

Parameters

Destination
[in/out] Pointer to the pointer to the destination value. The sign is ignored.
Exchange
[in] Specifies the exchange value. The sign is ignored.
Comperand
[in] Specifies the value to compare to Destination. The sign is ignored.

Return Values

The return value is the initial value of the destination.

Remarks

On a 64-bit system, the parameters are 64 bits and must be aligned on 64-bit boundaries; otherwise, the function will fail. On a 32-bit system, the parameters are 32 bits and must be aligned on 32-bit boundaries.

The interlocked functions provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The InterlockedCompareExchange function performs an atomic comparison of the Destination value with the Comperand value. If the Destination value is equal to the Comperand value, the Exchange value is stored in the address specified by Destination. Otherwise, no operation is performed.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd, InterlockedExchangePointer, InterlockedIncrement


InterlockedDecrement

The InterlockedDecrement function decrements (decreases by one) the value of the specified variable and checks the resulting value. The function prevents more than one thread from using the same variable simultaneously.

LONG InterlockedDecrement(
  LPLONG lpAddend   // variable address
);

Parameters

lpAddend
[in/out] Pointer to the variable to decrement.

Return Values

Windows 98, Windows NT 4.0 and later: The return value is the resulting decremented value.

Windows 95, Windows NT 3.51 and earlier: If the result of the operation is zero, the return value is zero. If the result of the operation is less than zero, the return value is negative, but it is not necessarily equal to the result. If the result of the operation is greater than zero, the return value is positive, but it is not necessarily equal to the result.

Remarks

The functions InterlockedDecrement, InterlockedCompareExchange, InterlockedExchange, InterlockedExchangeAdd, and InterlockedIncrement provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The variable pointed to by the lpAddend parameter must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems and any non-x86 systems.

MAPI: For more information, see Syntax and Limitations for Win32 Functions Useful in MAPI Development.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchange, InterlockedExchange, InterlockedExchangeAdd, InterlockedIncrement


InterlockedExchange

The InterlockedExchange function atomically exchanges a pair of values. The function prevents more than one thread from using the same variable simultaneously.

If you are exchanging pointer values, this function has been superseded by the InterlockedExchangePointer function.

LONG InterlockedExchange(
  LPLONG Target, // value to exchange
  LONG Value     // new value
);

Parameters

Target
[in/out] Pointer to the value to exchange. The function sets this variable to Value, and returns its prior value.
Value
[in] Specifies a new value for the variable pointed to by Target.

Return Values

The function returns the initial value pointed to by Target.

Remarks

The functions InterlockedExchange, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchangeAdd, and InterlockedIncrement provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The variable pointed to by the Target parameter must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems and any non-x86 systems.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchangeAdd, InterlockedExchangePointer, InterlockedIncrement


InterlockedExchangeAdd

The InterlockExchangeAdd function performs an atomic addition of an increment value to an addend variable. The function prevents more than one thread from using the same variable simultaneously.

LONG InterlockedExchangeAdd (
  LPLONG Addend,  // addend
  LONG Value      // increment value
);

Parameters

Addend
[in/out] Pointer to the number that will have Value added to it.
Value
[in] Specifies the number to be added to the variable pointed to by the Addend parameter.

Return Values

The return value is the initial value of the variable pointed to by the Addend parameter.

Remarks

The functions InterlockedExchangeAdd, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchange, and InterlockedIncrement provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The InterlockedExchangeAdd function performs an atomic addition of Value to the value pointed to by Addend. The result is stored in the address specified by Addend. The initial value of the variable pointed to by Addend is returned as the function value.

The variables for InterlockedExchangeAdd must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems and any non-x86 systems.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchange, InterlockedIncrement


InterlockedExchangePointer

The InterlockedExchangePointer function atomically exchanges a pair of values. The function prevents more than one thread from using the same variable simultaneously.

If you are exchanging pointer values, this function supersedes the InterlockedExchange function.

PVOID InterlockedExchangePointer(
  PVOID *Target,  // value to exchange
  PVOID Value     // new value
);

Parameters

Target
[in/out] Pointer to the pointer to the value to exchange. The function sets the value to Value.
Value
[in] Specifies a new value for Target.

Return Values

The function returns the initial value pointed to by Target.

Remarks

On a 64-bit system, the parameters are 64 bits and must be aligned on 64-bit boundaries; otherwise, the function will fail. On a 32-bit system, the parameters are 32 bits and must be aligned on 32-bit boundaries.

The interlocked functions provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.5 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchange, InterlockedCompareExchangePointer, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd, InterlockedIncrement


InterlockedIncrement

The InterlockedIncrement function increments (increases by one) the value of the specified variable and checks the resulting value. The function prevents more than one thread from using the same variable simultaneously.

LONG InterlockedIncrement(
  LPLONG lpAddend   // variable to increment
);

Parameters

lpAddend
[in/out] Pointer to the variable to increment.

Return Values

Windows 98, Windows NT 4.0 and later: The return value is the resulting incremented value.

Windows 95, Windows NT 3.51 and earlier: If the result of the operation is zero, the return value is zero. If the result of the operation is less than zero, the return value is negative, but it is not necessarily equal to the result. If the result of the operation is greater than zero, the return value is positive, but it is not necessarily equal to the result.

Remarks

The functions InterlockedIncrement, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchange, and InterlockedExchangeAdd provide a simple mechanism for synchronizing access to a variable that is shared by multiple threads. The threads of different processes can use this mechanism if the variable is in shared memory.

The variable pointed to by the lpAddend parameter must be aligned on a 32-bit boundary; otherwise, this function will fail on multiprocessor x86 systems and any non-x86 systems.

MAPI: For more information, see Syntax and Limitations for Win32 Functions Useful in MAPI Development.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, Interlocked Variable Access, InterlockedCompareExchange, InterlockedDecrement, InterlockedExchange, InterlockedExchangeAdd


LeaveCriticalSection

The LeaveCriticalSection function releases ownership of the specified critical section object.

VOID LeaveCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection   // critical section
);

Parameters

lpCriticalSection
[in/out] Pointer to the critical section object.

Return Values

This function does not return a value.

Remarks

The threads of a single process can use a critical-section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical-section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function to initialize the object.

A thread uses the EnterCriticalSection or TryEnterCriticalSection function to acquire ownership of a critical section object. To release its ownership, the thread must call LeaveCriticalSection once for each time that it entered the critical section.

If a thread calls LeaveCriticalSection when it does not have ownership of the specified critical section object, an error occurs that may cause another thread using EnterCriticalSection to wait indefinitely.

Any thread of the process can use the DeleteCriticalSection function to release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.

For an example that uses LeaveCriticalSection, see Using Critical Section Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, DeleteCriticalSection, EnterCriticalSection, InitializeCriticalSection, InitializeCriticalSectionAndSpinCount, TryEnterCriticalSection


MsgWaitForMultipleObjects

The MsgWaitForMultipleObjects function returns when one of the following occurs:

  • Either any one or all of the specified objects are in the signaled state. The objects can include input event objects, which you specify using the dwWakeMask parameter.
  • The time-out interval elapses.

To enter an alertable wait state, use the MsgWaitForMultipleObjectsEx function.

Note MsgWaitForMultipleObjects does not return if there is unread input of the specified type in the message queue after the thread has called a function to check the queue. This is because functions such as PeekMessage, GetMessage, GetQueueStatus, and WaitMessage check the queue and then change the state information for the queue so that the input is no longer considered new. A subsequent call to MsgWaitForMultipleObjects will not return until new input of the specified type arrives. The existing unread input (received prior to the last time the thread checked the queue) is ignored.

DWORD MsgWaitForMultipleObjects(
  DWORD nCount,          // number of handles in array
  CONST HANDLE pHandles, // object-handle array
  BOOL bWaitAll,         // wait option
  DWORD dwMilliseconds,  // time-out interval
  DWORD dwWakeMask       // input-event type
);

Parameters

nCount
[in] Specifies the number of object handles in the array pointed to by pHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS minus one.
pHandles
[in] Pointer to an array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles of objects of different types. It may not contain multiple copies of the same handle.

If one of these handles is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000 or later: The handles must have SYNCHRONIZE access. For more information, see Standard Access Rights.

Windows 95/98/Me: No handle may be a duplicate of another handle created using DuplicateHandle.

bWaitAll
[in] Specifies the wait type. If TRUE, the function returns when the states of all objects in the pHandles array have been set to signaled and an input event has been received. If FALSE, the function returns when the state of any one of the objects is set to signaled or an input event has been received. In this case, the return value indicates the object whose state caused the function to return.
dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the criteria specified by the bWaitAll or dwWakeMask parameter have not been met. If dwMilliseconds is zero, the function tests the states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.
dwWakeMask
[in] Specifies input types for which an input event object handle will be added to the array of object handles. This parameter can be any combination of the following values.
Value | Meaning
QS_ALLEVENTS An input, WM_TIMER, WM_PAINT, WM_HOTKEY, or posted message is in the queue.

This value is a combination of QS_INPUT, QS_POSTMESSAGE, QS_TIMER, QS_PAINT, and QS_HOTKEY.
QS_ALLINPUT Any message is in the queue.

This value is a combination of QS_INPUT, QS_POSTMESSAGE, QS_TIMER, QS_PAINT, QS_HOTKEY, and QS_SENDMESSAGE.
QS_ALLPOSTMESSAGE A posted message is in the queue.

This value is cleared when you call GetMessage or PeekMessage, whether or not you are filtering messages.
QS_HOTKEY | A WM_HOTKEY message is in the queue.
QS_INPUT An input message is in the queue.

This value is a combination of QS_MOUSE and QS_KEY.

Whistler: This value also includes QS_RAWINPUT.
QS_KEY | A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the queue.
QS_MOUSE A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).

This value is a combination of QS_MOUSEMOVE and QS_MOUSEBUTTON.
QS_MOUSEBUTTON | A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEMOVE | A WM_MOUSEMOVE message is in the queue.
QS_PAINT | A WM_PAINT message is in the queue.
QS_POSTMESSAGE A posted message is in the queue.

This value is cleared when you call GetMessage or PeekMessage without filtering messages.
QS_RAWINPUT | Whistler: A raw input message is in the queue. For more information, see Raw Input.
QS_SENDMESSAGE | A message sent by another thread or application is in the queue.
QS_TIMER | A WM_TIMER message is in the queue.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. The successful return value is one of the following:

Value | Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1) | If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled. If bWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the pHandles array index of the object that satisfied the wait.
WAIT_OBJECT_0 + nCount | New input of the type specified in the dwWakeMask parameter is available in the thread's input queue. Functions such as PeekMessage, GetMessage, and WaitMessage mark messages in the queue as old messages. Therefore, after you call one of these functions, a subsequent call to MsgWaitForMultipleObjects will not return until new input of the specified type arrives. This value is also returned upon the occurrence of a system event that requires the thread's action, such as foreground activation. Therefore, MsgWaitForMultipleObjects can return even though no appropriate input is available and even if dwWaitMask is set to 0. If this occurs, call PeekMessage or GetMessage to process the system event before trying the call to MsgWaitForMultipleObjects again.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount – 1) | If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object. If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the pHandles array index of an abandoned mutex object that satisfied the wait.
WAIT_TIMEOUT | The time-out interval elapsed and the conditions specified by the bWaitAll and dwWakeMask parameters were not satisfied.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

The MsgWaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the conditions of the wait criteria to be met.

When bWaitAll is TRUE, the function does not modify the states of the specified objects until the states of all objects have been set to signaled. For example, a mutex can be signaled, but the thread does not get ownership until the states of the other objects have also been set to signaled. In the meantime, some other thread may get ownership of the mutex, thereby setting its state to nonsignaled.

When bWaitAll is TRUE, the function's wait is completed only when the states of all objects have been set to signaled and an input event has been received. Therefore, setting bWaitAll to TRUE prevents input from being processed until the state of all objects in the pHandles array have been set to signaled. For this reason, if you set bWaitAll to TRUE, you should use a short timeout value in dwMilliseconds. If you have a thread that creates windows waiting for all objects in the pHandles array, including input events specified by dwWakeMask, with no timeout interval, the system will deadlock. This is because threads that create windows must process messages. DDE sends message to all windows in the system. Therefore, if a thread creates windows, do not set the bWaitAll parameter to TRUE in calls to MsgWaitForMultipleObjects made from that thread.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When bWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

The MsgWaitForMultipleObjects function can specify handles of any of the following object types in the pHandles array:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

For more information, see Synchronization Objects.

The QS_ALLPOSTMESSAGE and QS_POSTMESSAGE flags differ in when they are cleared. QS_POSTMESSAGE is cleared when you call GetMessage or PeekMessage, whether or not you are filtering messages. QS_ALLPOSTMESSAGE is cleared when you call GetMessage or PeekMessage without filtering messages (wMsgFilterMin and wMsgFilterMax are 0). This can be useful when you call PeekMessage multiple times to get messages in different ranges.

For an example that uses MsgWaitForMultipleObjects, see Waiting in a Message Loop.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Synchronization Overview, Synchronization Functions, MsgWaitForMultipleObjectsEx


MsgWaitForMultipleObjectsEx

The MsgWaitForMultipleObjectsEx function returns when one of the following occurs:

  • Either any one or all of the specified objects are in the signaled state. The array of objects can include input event objects, which you specify using the dwWakeMask parameter.
  • An I/O completion routine or asynchronous procedure call (APC) is queued to the thread.
  • The time-out interval elapses.

Note MsgWaitForMultipleObjectsEx does not return if there is unread input of the specified type in the message queue after the thread has called a function to check the queue, unless you use the MWMO_INPUTAVAILABLE flag. This is because functions such as PeekMessage, GetMessage, GetQueueStatus, and WaitMessage check the queue and then change the state information for the queue so that the input is no longer considered new. A subsequent call to MsgWaitForMultipleObjectsEx will not return until new input of the specified type arrives, unless you use the MWMO_INPUTAVAILABLE flag. If this flag is not used, the existing unread input (received prior to the last time the thread checked the queue) is ignored.

DWORD MsgWaitForMultipleObjectsEx(
  DWORD nCount,          // number of handles in array
  CONST HANDLE pHandles, // object-handle array
  DWORD dwMilliseconds,  // time-out interval
  DWORD dwWakeMask,      // input-event type
  DWORD dwFlags          // wait options
);

Parameters

nCount
[in] Specifies the number of object handles in the array pointed to by pHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS minus one.
pHandles
[in] Pointer to an array of object handles. For a list of the object types whose handles you can specify, see the Remarks section later in this topic. The array can contain handles to multiple types of objects. It may not contain multiple copies of the same handle.

If one of these handles is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000 or later: The handles must have SYNCHRONIZE access. For more information, see Standard Access Rights.

dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the conditions specified by the dwWakeMask and dwFlags parameters are not met. If dwMilliseconds is zero, the function tests the states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.
dwWakeMask
[in] Specifies input types for which an input event object handle will be added to the array of object handles. This parameter can be any combination of the following values:
Value | Meaning
QS_ALLEVENTS An input, WM_TIMER, WM_PAINT, WM_HOTKEY, or posted message is in the queue.

This value is a combination of QS_INPUT, QS_POSTMESSAGE, QS_TIMER, QS_PAINT, and QS_HOTKEY.
QS_ALLINPUT Any message is in the queue.

This value is a combination of QS_INPUT, QS_POSTMESSAGE, QS_TIMER, QS_PAINT, QS_HOTKEY, and QS_SENDMESSAGE.
QS_ALLPOSTMESSAGE | A posted message (other than those listed here) is in the queue.
QS_HOTKEY | A WM_HOTKEY message is in the queue.
QS_INPUT An input message is in the queue.

This value is a combination of QS_MOUSE and QS_KEY.
QS_KEY | A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN message is in the queue.
QS_MOUSE A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on) is in the queue.

This value is a combination of QS_MOUSEMOVE and QS_MOUSEBUTTON.
QS_MOUSEBUTTON | A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on) is in the queue.
QS_MOUSEMOVE | A WM_MOUSEMOVE message is in the queue.
QS_PAINT | A WM_PAINT message is in the queue.
QS_POSTMESSAGE | A posted message (other than those just listed) is in the queue.
QS_SENDMESSAGE | A message sent by another thread or application is in the queue.
QS_TIMER | A WM_TIMER message is in the queue.

dwFlags
[in] Specifies the wait type. This parameter can be any combination of the following values:
Value | Meaning
0 | The function returns when any one of the objects is signaled. The return value indicates the object whose state caused the function to return.
MWMO_WAITALL | The function returns when all objects in the pHandles array are signaled and an input event has been received, all at the same time.
MWMO_ALERTABLE | The function also returns if an APC has been queued to the thread with QueueUserAPC.
MWMO_INPUTAVAILABLE | Windows 98/Me, Windows 2000 or later: The function returns if input exists for the queue, even if the input has been seen (but not removed) using a call to another function, such as PeekMessage.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. The successful return value is one of the following:

Value | Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount - 1) | If the MWMO_WAITALL flag is used, the return value indicates that the state of all specified objects is signaled. Otherwise, the return value minus WAIT_OBJECT_0 indicates the pHandles array index of the object that caused the function to return.
WAIT_OBJECT_0 + nCount | New input of the type specified in the dwWakeMask parameter is available in the thread's input queue. Functions such as PeekMessage, GetMessage, GetQueueStatus, and WaitMessage mark messages in the queue as old messages. Therefore, after you call one of these functions, a subsequent call to MsgWaitForMultipleObjectsEx will not return until new input of the specified type arrives. This value is also returned upon the occurrence of a system event that requires the thread's action, such as foreground activation. Therefore, MsgWaitForMultipleObjectsEx can return even though no appropriate input is available and even if dwWaitMask is set to 0. If this occurs, call PeekMessage or GetMessage to process the system event before trying the call to MsgWaitForMultipleObjectsEx again.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount - 1) | If the MWMO_WAITALL flag is used, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object. Otherwise, the return value minus WAIT_ABANDONED_0 indicates the pHandles array index of an abandoned mutex object that caused the function to return.
WAIT_IO_COMPLETION | The wait was ended by one or more user-mode asynchronous procedure calls (APC) queued to the thread.
WAIT_TIMEOUT | The time-out interval elapsed, but the conditions specified by the dwFlags and dwWakeMask parameters were not met.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

The MsgWaitForMultipleObjectsEx function determines whether the conditions specified by dwWakeMask and dwFlags have been met. If the conditions have not been met, the calling thread enters the wait state. It uses no processor time while waiting for one of the conditions to be met or for the time-out interval to elapse.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the system decreases the count of a semaphore object by one. When dwFlags is zero, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

The MsgWaitForMultipleObjectsEx function can specify handles of any of the following object types in the pHandles array:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

For more information, see Synchronization Objects.

The QS_ALLPOSTMESSAGE and QS_POSTMESSAGE flags differ in when they are cleared. QS_POSTMESSAGE is cleared when you call GetMessage or PeekMessage, whether or not you are filtering messages. QS_ALLPOSTMESSAGE is cleared when you call GetMessage or PeekMessage without filtering messages (wMsgFilterMin and wMsgFilterMax are 0). This can be useful when you call PeekMessage multiple times to get messages in different ranges.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.

See Also

Synchronization Overview, Synchronization Functions


OpenEvent

The OpenEvent function opens an existing named event object.

HANDLE OpenEvent(
  DWORD dwDesiredAccess,  // access
  BOOL bInheritHandle,    // inheritance option
  LPCTSTR lpName          // object name
);

Parameters

dwDesiredAccess
[in] Specifies the requested access to the event object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values.
Access | Description
EVENT_ALL_ACCESS | Specifies all possible access flags for the event object.
EVENT_MODIFY_STATE | Enables use of the event handle in the SetEvent and ResetEvent functions to modify the event's state.
SYNCHRONIZE | Windows NT/2000 or later: Enables use of the event handle in any of the wait functions to wait for the event's state to be signaled.

bInheritHandle
[in] Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.
lpName
[in] Pointer to a null-terminated string that names the event to be opened. Name comparisons are case sensitive.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly open an object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the event object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenEvent function enables multiple processes to open handles of the same event object. The function succeeds only if some process has already created the event by using the CreateEvent function. The calling process can use the returned handle in any function that requires a handle to an event object, subject to the limitations of the access specified in the dwDesiredAccess parameter.

The handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The event object is destroyed when its last handle has been closed.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CloseHandle, CreateEvent, CreateProcess, DuplicateHandle, PulseEvent, ResetEvent, SetEvent, Object Names


OpenMutex

The OpenMutex function opens an existing named mutex object.

HANDLE OpenMutex(
  DWORD dwDesiredAccess,  // access
  BOOL bInheritHandle,    // inheritance option
  LPCTSTR lpName          // object name
);

Parameters

dwDesiredAccess
[in] Specifies the requested access to the mutex object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values.
Access | Description
MUTEX_ALL_ACCESS | Specifies all possible access flags for the mutex object.
SYNCHRONIZE | Windows NT/2000 or later: Enables use of the mutex handle in any of the wait functions to acquire ownership of the mutex, or in the ReleaseMutex function to release ownership.

bInheritHandle
[in] Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.
lpName
[in] Pointer to a null-terminated string that names the mutex to be opened. Name comparisons are case sensitive.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly open an object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the mutex object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenMutex function enables multiple processes to open handles of the same mutex object. The function succeeds only if some process has already created the mutex by using the CreateMutex function. The calling process can use the returned handle in any function that requires a handle to a mutex object, such as the wait functions, subject to the limitations of the access specified in the dwDesiredAccess parameter.

The handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.

For an example that uses OpenMutex, see Using Named Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CloseHandle, CreateMutex, CreateProcess, DuplicateHandle, ReleaseMutex, Object Names


OpenSemaphore

The OpenSemaphore function opens an existing named semaphore object.

HANDLE OpenSemaphore(
  DWORD dwDesiredAccess,  // access
  BOOL bInheritHandle,    // inheritance option
  LPCTSTR lpName          // object name
);

Parameters

dwDesiredAccess
[in] Specifies the requested access to the semaphore object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values.
Access | Description
SEMAPHORE_ALL_ACCESS | Specifies all possible access flags for the semaphore object.
SEMAPHORE_MODIFY_STATE | Enables use of the semaphore handle in the ReleaseSemaphore function to modify the semaphore's count.
SYNCHRONIZE | Windows NT/2000 or later: Enables use of the semaphore handle in any of the wait functions to wait for the semaphore's state to be signaled.

bInheritHandle
[in] Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.
lpName
[in] Pointer to a null-terminated string that names the semaphore to be opened. Name comparisons are case sensitive.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly open an object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the semaphore object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenSemaphore function enables multiple processes to open handles of the same semaphore object. The function succeeds only if some process has already created the semaphore by using the CreateSemaphore function. The calling process can use the returned handle in any function that requires a handle to a semaphore object, such as the wait functions, subject to the limitations of the access specified in the dwDesiredAccess parameter.

The handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CloseHandle, CreateSemaphore, DuplicateHandle, ReleaseSemaphore, Object Names


OpenWaitableTimer

The OpenWaitableTimer function opens an existing named waitable timer object.

HANDLE OpenWaitableTimer(
  DWORD dwDesiredAccess,  // access
  BOOL bInheritHandle,    // inheritance option
  LPCTSTR lpTimerName     // object name
);

Parameters

dwDesiredAccess
[in] Specifies the requested access to the timer object. For systems that support object security, the function fails if the security descriptor of the specified object does not permit the requested access for the calling process.

This parameter can be any combination of the following values.
Value | Meaning
TIMER_ALL_ACCESS | Specifies all possible access rights for the timer object.
TIMER_MODIFY_STATE | Enables use of the timer handle in the SetWaitableTimer and CancelWaitableTimer functions to modify the timer's state.
TIMER_QUERY_STATE | Reserved for future use.
SYNCHRONIZE | Windows NT/2000 or later: Enables use of the timer handle in any of the wait functions to wait for the timer's state to be signaled.

bInheritHandle
[in] Specifies whether the returned handle is inheritable. If TRUE, a process created by the CreateProcess function can inherit the handle; otherwise, the handle cannot be inherited.
lpTimerName
[in] Pointer to a null-terminated string specifying the name of the timer object. The name is limited to MAX_PATH characters. Name comparison is case sensitive.

Terminal Services: The name can have a "Global\" or "Local\" prefix to explicitly open an object in the global or session name space. The remainder of the name can contain any character except the backslash character (\). For more information, see Kernel Object Name Spaces.

Windows 2000 or later: If Terminal Services is not running, the "Global\" and "Local\" prefixes are ignored. The remainder of the name can contain any character except the backslash character.

Windows NT 4.0 and earlier: The name can contain any character except the backslash character.

Windows 95/98/Me: The name can contain any character except the backslash character. The empty string ("") is a valid object name.

Return Values

If the function succeeds, the return value is a handle to the timer object.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Remarks

The OpenWaitableTimer function enables multiple processes to open handles to the same timer object. The function succeeds only if some process has already created the timer using the CreateWaitableTimer function. The calling process can use the returned handle in any function that requires the handle to a timer object, such as the wait functions, subject to the limitations of the access specified in the dwDesiredAccess parameter.

The returned handle can be duplicated by using the DuplicateHandle function. Use the CloseHandle function to close the handle. The system closes the handle automatically when the process terminates. The timer object is destroyed when its last handle has been closed.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.
Unicode: Implemented as Unicode and ANSI versions on Windows NT/2000.

See Also

Synchronization Overview, Synchronization Functions, CancelWaitableTimer, CloseHandle, CreateProcess, CreateWaitableTimer, DuplicateHandle, SetWaitableTimer, Object Names


PulseEvent

The PulseEvent function sets the specified event object to the signaled state and then resets it to the nonsignaled state after releasing the appropriate number of waiting threads.

BOOL PulseEvent(
  HANDLE hEvent   // handle to event object
);

Parameters

hEvent
[in] Handle to the event object. The CreateEvent or OpenEvent function returns this handle.

Windows NT/2000 or later: The handle must have EVENT_MODIFY_STATE access. For more information, see Synchronization Object Security and Access Rights.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

For a manual-reset event object, all waiting threads that can be released immediately are released. The function then resets the event object's state to nonsignaled and returns.

For an auto-reset event object, the function resets the state to nonsignaled and returns after releasing a single waiting thread, even if multiple threads are waiting.

If no threads are waiting, or if no thread can be released immediately, PulseEvent simply sets the event object's state to nonsignaled and returns.

Note that for a thread using the multiple-object wait functions to wait for all specified objects to be signaled, PulseEvent can set the event object's state to signaled and reset it to nonsignaled without causing the wait function to return. This happens if not all of the specified objects are simultaneously signaled.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateEvent, OpenEvent, ResetEvent, SetEvent


QueueUserAPC

The QueueUserAPC function adds a user-mode asynchronous procedure call (APC) object to the APC queue of the specified thread.

DWORD QueueUserAPC(
  PAPCFUNC pfnAPC,  // APC function
  HANDLE hThread,   // handle to thread
  ULONG_PTR dwData  // APC function parameter
);

Parameters

pfnAPC
[in] Pointer to the application-supplied APC function to be called when the specified thread performs an alertable wait operation. For more information, see APCProc.
hThread
[in] Specifies the handle to the thread. The handle must have THREAD_SET_CONTEXT access. For more information, see Synchronization Object Security and Access Rights.
dwData
[in] Specifies a single value that is passed to the APC function pointed to by the pfnAPC parameter.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. There are no error values defined for this function that can be retrieved by calling GetLastError.

Remarks

The APC support provided in the operating system allows an application to queue an APC object to a thread. Each thread has its own APC queue. The queuing of an APC is a request for the thread to call the APC function. The operating system issues a software interrupt to direct the thread to call the APC function.

When a user-mode APC is queued, the thread is not directed to call the APC function unless it is in an alertable state. After the thread is in an alertable state, the thread handles all pending APCs in first in, first out (FIFO) order, and the wait operation returns WAIT_IO_COMPLETION. A thread enters an alertable state by using SleepEx, SignalObjectAndWait, WaitForSingleObjectEx, WaitForMultipleObjectsEx, or MsgWaitForMultipleObjectsEx to perform an alertable wait operation.

If an application queues an APC before the thread begins running, the thread begins by calling the APC function. After the thread calls an APC function, it calls the APC functions for all APCs in its APC queue.

When the thread is terminated using the ExitThread or TerminateThread function, the APCs in its APC queue are lost. The APC functions are not called.

Note that the ReadFileEx, SetWaitableTimer, and WriteFileEx functions are implemented using an APC as the completion notification callback mechanism.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, APCProc, MsgWaitForMultipleObjectsEx, ReadFileEx, SetWaitableTimer, SleepEx, WaitForMultipleObjectsEx, WaitForSingleObjectEx, WriteFileEx


RegisterWaitForSingleObject

The RegisterWaitForSingleObject function directs a wait thread in the thread pool to wait on the object. The wait thread queues the specified callback function to the thread pool when one of the following occurs:

  • The specified object is in the signaled state.
  • The time-out interval elapses.
BOOL RegisterWaitForSingleObject(
  PHANDLE phNewWaitObject,       // wait handle
  HANDLE hObject,                // handle to object
  WAITORTIMERCALLBACK Callback,  // timer callback function
  PVOID Context                  // callback function parameter
  ULONG dwMilliseconds,          // time-out interval
  ULONG dwFlags                  // options
);

Parameters

phNewWaitObject
[out] Pointer to a variable that receives a wait handle on return. Note that a wait handle cannot be used in functions that require an object handle, such as CloseHandle.
hObject
[in] Handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.

If this handle is closed while the wait is still pending, the function's behavior is undefined.

Callback
[in] Pointer to the application-defined function of type WAITORTIMERCALLBACK to be executed when hObject is in the signaled state, or dwMilliseconds elapses. For more information, see WaitOrTimerCallback.
Context
[in] Specifies a single value that is passed to the callback function.
dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If dwMilliseconds is zero, the function tests the object's state and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.
dwFlags
[in] Specifies how the operation is to be performed. This parameter can be one or more of the following values.
Value | Meaning
WT_EXECUTEDEFAULT | By default, the callback function is queued to a non-I/O worker thread.
WT_EXECUTEINWAITTHREAD The callback function is invoked by the wait thread itself. This flag should be used only for short tasks or it could affect other wait operations.

Deadlocks can occur if some other thread acquires an exclusive lock and calls the UnregisterWait or UnregisterWaitEx function while the callback function is trying to acquire the same lock.

WT_EXECUTEINIOTHREAD The callback function is queued to an I/O worker thread. This flag should be used if the function should be executed in a thread that waits in an alertable state.

The callback function is queued as an APC. Be sure to address reentrancy issues if the function performs an alertable wait operation.

WT_EXECUTEINPERSISTENTTHREAD The callback function is queued to a thread that never terminates. This flag should be used only for short tasks or it could affect other wait operations.

Note that currently no worker thread is persistent, although no worker thread will terminate if there are any pending I/O requests.
WT_EXECUTELONGFUNCTION | Specifies that the callback function can perform a long wait. This flag helps the system to decide if it should create a new thread.
WT_EXECUTEONLYONCE | The thread will no longer wait on the handle after the callback function has been called once. Otherwise, the timer is reset every time the wait operation completes until the wait operation is canceled.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. There are no error values defined for this function that can be retrieved by calling GetLastError.

Remarks

New wait threads are created automatically when required. The wait operation is performed by a wait thread from the thread pool. The callback routine is executed by a worker thread when the object's state becomes signaled or the time-out interval elapses. If dwFlags is not WT_EXECUTEONLYONCE, the timer is reset every time the event is signaled or the time-out interval elapses.

To cancel the wait operation, call the UnregisterWait or UnregisterWaitEx function. Do not make a blocking call to either of these functions from within the callback function.

Note that you should not pulse an event object passed to RegisterWaitForSingleObject, because the wait thread might not detect that the event is signaled before it is reset. You should not register a manual reset event unless you set the WT_EXECUTEONLYONCE or WT_EXECUTEINWAITTHREAD flag.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled state caused the wait condition to be satisfied. For example, the count of a semaphore object is decreased by one.

The RegisterWaitForSingleObject function can wait for the following objects:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

For more information, see Synchronization Objects.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, UnregisterWait, UnregisterWaitEx, WaitForMultipleObjects, WaitOrTimerCallback, Thread Pooling


ReleaseMutex

The ReleaseMutex function releases ownership of the specified mutex object.

BOOL ReleaseMutex(
  HANDLE hMutex   // handle to mutex
);

Parameters

hMutex
[in] Handle to the mutex object. The CreateMutex or OpenMutex function returns this handle.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The ReleaseMutex function fails if the calling thread does not own the mutex object.

A thread gets ownership of a mutex by specifying a handle to the mutex in one of the wait functions. The thread that creates a mutex object can also get immediate ownership without using one of the wait functions. When the owning thread no longer needs to own the mutex object, it calls the ReleaseMutex function.

While a thread has ownership of a mutex, it can specify the same mutex in additional wait-function calls without blocking its execution. This prevents a thread from deadlocking itself while waiting for a mutex that it already owns. However, to release its ownership, the thread must call ReleaseMutex once for each time that the mutex satisfied a wait.

For an example that uses ReleaseMutex, see Using Mutex Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateMutex


ReleaseSemaphore

The ReleaseSemaphore function increases the count of the specified semaphore object by a specified amount.

BOOL ReleaseSemaphore(
  HANDLE hSemaphore,       // handle to semaphore
  LONG lReleaseCount,      // count increment amount
  LPLONG lpPreviousCount   // previous count
);

Parameters

hSemaphore
[in] Handle to the semaphore object. The CreateSemaphore or OpenSemaphore function returns this handle.

Windows NT/2000 or later: This handle must have SEMAPHORE_MODIFY_STATE access. For more information, see Synchronization Object Security and Access Rights.

lReleaseCount
[in] Specifies the amount by which the semaphore object's current count is to be increased. The value must be greater than zero. If the specified amount would cause the semaphore's count to exceed the maximum count that was specified when the semaphore was created, the count is not changed and the function returns FALSE.
lpPreviousCount
[out] Pointer to a variable to receive the previous count for the semaphore. This parameter can be NULL if the previous count is not required.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The state of a semaphore object is signaled when its count is greater than zero and nonsignaled when its count is equal to zero. The process that calls the CreateSemaphore function specifies the semaphore's initial count. Each time a waiting thread is released because of the semaphore's signaled state, the count of the semaphore is decreased by one.

Typically, an application uses a semaphore to limit the number of threads using a resource. Before a thread uses the resource, it specifies the semaphore handle in a call to one of the wait functions. When the wait function returns, it decreases the semaphore's count by one. When the thread has finished using the resource, it calls ReleaseSemaphore to increase the semaphore's count by one.

Another use of ReleaseSemaphore is during an application's initialization. The application can create a semaphore with an initial count of zero. This sets the semaphore's state to nonsignaled and blocks all threads from accessing the protected resource. When the application finishes its initialization, it uses ReleaseSemaphore to increase the count to its maximum value, to permit normal access to the protected resource.

For an example that uses ReleaseSemaphore, see Using Semaphore Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateSemaphore, OpenSemaphore


ResetEvent

The ResetEvent function sets the specified event object to the nonsignaled state.

BOOL ResetEvent(
  HANDLE hEvent   // handle to event
);

Parameters

hEvent
[in] Handle to the event object. The CreateEvent or OpenEvent function returns this handle.

Windows NT/2000 or later: The handle must have EVENT_MODIFY_STATE access. For more information, see Synchronization Object Security and Access Rights.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The state of an event object remains nonsignaled until it is explicitly set to signaled by the SetEvent or PulseEvent function. This nonsignaled state blocks the execution of any threads that have specified the event object in a call to one of the wait functions.

The ResetEvent function is used primarily for manual-reset event objects, which must be set explicitly to the nonsignaled state. Auto-reset event objects automatically change from signaled to nonsignaled after a single waiting thread is released.

For an example that uses ResetEvent, see Using Event Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateEvent, OpenEvent, PulseEvent, SetEvent


SetCriticalSectionSpinCount

The SetCriticalSectionSpinCount function sets the spin count for the specified critical section.

DWORD SetCriticalSectionSpinCount(
  LPCRITICAL_SECTION lpCriticalSection, // critical section
  DWORD dwSpinCount                     // spin count
);

Parameters

lpCriticalSection
[in/out] Pointer to the critical section object.
dwSpinCount
[in] Specifies the spin count for the critical section object. On single-processor systems, the spin count is ignored and the critical section spin count is set to 0. On multiprocessor systems, if the critical section is unavailable, the calling thread will spin dwSpinCount times before performing a wait operation on a semaphore associated with the critical section. If the critical section becomes free during the spin operation, the calling thread avoids the wait operation.

Return Values

The function returns the previous spin count for the critical section.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function to initialize the object. You can subsequently modify the spin count by calling the SetCriticalSectionSpinCount function.

The spin count is useful for critical sections of short duration that can experience high levels of contention. Consider a worst-case scenario, in which an application on an SMP system has two or three threads constantly allocating and releasing memory from the heap. The application serializes the heap with a critical section. In the worst-case scenario, contention for the critical section is constant, and each thread makes an expensive call to the WaitForSingleObject function. However, if the spin count is set properly, the calling thread will not immediately call WaitForSingleObject when contention occurs. Instead, the calling thread can acquire ownership of the critical section if it is released during the spin operation.

You can improve performance significantly by choosing a small spin count for a critical section of short duration. The heap manager uses a spin count of roughly 4000 for its per-heap critical sections. This gives great performance and scalability in almost all worst-case scenarios.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 SP3 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, InitializeCriticalSection, InitializeCriticalSectionAndSpinCount, WaitForSingleObject


SetEvent

The SetEvent function sets the specified event object to the signaled state.

BOOL SetEvent(
  HANDLE hEvent   // handle to event
);

Parameters

hEvent
[in] Handle to the event object. The CreateEvent or OpenEvent function returns this handle.

Windows NT/2000 or later: The handle must have EVENT_MODIFY_STATE access. For more information, see Synchronization Object Security and Access Rights.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

The state of a manual-reset event object remains signaled until it is set explicitly to the nonsignaled state by the ResetEvent function. Any number of waiting threads, or threads that subsequently begin wait operations for the specified event object by calling one of the wait functions, can be released while the object's state is signaled.

The state of an auto-reset event object remains signaled until a single waiting thread is released, at which time the system automatically sets the state to nonsignaled. If no threads are waiting, the event object's state remains signaled.

For an example that uses SetEvent, see Using Event Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CreateEvent, OpenEvent, PulseEvent, ResetEvent


SetWaitableTimer

The SetWaitableTimer function activates the specified waitable timer. When the due time arrives, the timer is signaled and the thread that set the timer calls the optional completion routine.

BOOL SetWaitableTimer(
  HANDLE hTimer,                          // handle to timer
  const LARGE_INTEGER *pDueTime,          // timer due time
  LONG lPeriod,                           // timer interval
  PTIMERAPCROUTINE pfnCompletionRoutine,  // completion routine
  LPVOID lpArgToCompletionRoutine,        // completion routine parameter
  BOOL fResume                            // resume state
);

Parameters

hTimer
[in] Handle to the timer object. The CreateWaitableTimer or OpenWaitableTimer function returns this handle.
pDueTime
[in] Specifies when the state of the timer is to be set to signaled, in 100 nanosecond intervals. Use the format described by the FILETIME structure. Positive values indicate absolute time. Be sure to use a UTC-based absolute time, as the system uses UTC-based time internally. Negative values indicate relative time. The actual timer accuracy depends on the capability of your hardware. For more information about UTC-based time, see System Time.
lPeriod
[in] Specifies the period of the timer, in milliseconds. If lPeriod is zero, the timer is signaled once. If lPeriod is greater than zero, the timer is periodic. A periodic timer automatically reactivates each time the period elapses, until the timer is canceled using the CancelWaitableTimer function or reset using SetWaitableTimer. If lPeriod is less than zero, the function fails.
pfnCompletionRoutine
[in] Pointer to an optional completion routine. The completion routine is application-defined function of type PTIMERAPCROUTINE to be executed when the timer is signaled. For more information on the timer callback function, see TimerAPCProc.
lpArgToCompletionRoutine
[in] Pointer to the structure that is passed to the optional completion routine.
fResume
[in] Specifies whether to restore a system in suspended power conservation mode when the timer state is set to signaled. If fResume is TRUE on a platform that does not support a restore, the call will succeed, but GetLastError returns ERROR_NOT_SUPPORTED.

Return Value

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

Timers are initially inactive. To activate a timer, call SetWaitableTimer. If the timer is already active when you call SetWaitableTimer, the timer is stopped, then it is reactivated. Stopping the timer in this manner does not set the timer state to signaled, so threads blocked in a wait operation on the timer remain blocked.

When the specified due time arrives, the timer becomes inactive and the APC is queued to the thread that set the timer. The state of the timer is set to signaled, the timer is reactivated using the specified period, and the thread that set the timer calls the completion routine when it enters an alertable wait state. For more information, see QueueUserAPC.

If the thread that set the timer exits before the timer elapses, the timer is cancelled. If you call SetWaitableTimer on a timer that has been set by another thread and that thread is not in an alertable state, the completion routine is cancelled.

When a manual-reset timer is set to the signaled state, it remains in this state until SetWaitableTimer is called to reset the timer. As a result, a periodic manual-reset timer is set to the signaled state when the initial due time arrives and remains signaled until it is reset. When a synchronization timer is set to the signaled state, it remains in this state until a thread completes a wait operation on the timer object.

Example

For an example that uses SetWaitableTimer, see Using Waitable Timer Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, CancelWaitableTimer, CreateWaitableTimer, FILETIME, OpenWaitableTimer, TimerAPCProc


SignalObjectAndWait

The SignalObjectAndWait function allows the caller to atomically signal an object and wait on another object.

DWORD SignalObjectAndWait(
  HANDLE hObjectToSignal,  // handle to object to signal
  HANDLE hObjectToWaitOn,  // handle to object to watch
  DWORD dwMilliseconds,    // time-out interval
  BOOL bAlertable          // alertable option
);

Parameters

hObjectToSignal
[in] Specifies the handle to the object to signal. This object can be a semaphore, a mutex, or an event.

Windows NT/2000 or later: If the handle is a semaphore, SEMAPHORE_MODIFY_STATE access is required. If the handle is an event, EVENT_MODIFY_STATE access is required. If the handle is a mutex, SYNCHRONIZE access is assumed, because only the owner of a mutex may release it. For more information, see Synchronization Object Security and Access Rights.

hObjectToWaitOn
[in] Specifies the handle to the object to wait for. For a list of the object types whose handles you can specify, see the Remarks section.
dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled and no completion or asynchronous procedure call (APC) objects are queued. If dwMilliseconds is zero, the function tests the object's state, checks for queued completion routines or APCs, and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.
bAlertable
[in] Specifies whether the function returns when the system queues an I/O completion routine or an APC for the calling thread. If TRUE, the function returns and the thread calls the completion routine or APC function. If FALSE, the function does not return, and the thread does not call the completion routine or APC function.

A completion routine is queued when the ReadFileEx or WriteFileEx function in which it was specified has completed. The wait function returns and the completion routine is called only if bAlertable is TRUE, and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call QueueUserAPC.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following:

Value | Meaning
WAIT_ABANDONED | The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_IO_COMPLETION | The wait was ended by one or more user-mode asynchronous procedure calls (APC) queued to the thread.
WAIT_OBJECT_0 | The state of the specified object is signaled.
WAIT_TIMEOUT | The time-out interval elapsed, and the object's state is nonsignaled.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

A completion routine is queued for execution when the ReadFileEx or WriteFileEx function in which it was specified has been completed. The wait function returns and the completion routine is executed only if bAlertable is TRUE, and the calling thread is the thread that initiated the read or write operation.

The SignalObjectAndWait function can wait for the following objects:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

For more information, see Synchronization Objects.

Use caution when using the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than SignalObjectAndWait.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx


TimerAPCProc

The TimerAPCProc function is an application-defined timer completion routine. Specify this address when calling the SetWaitableTimer function. The PTIMERAPCROUTINE type defines a pointer to this callback function. TimerAPCProc is a placeholder for the application-defined function name.

VOID CALLBACK TimerAPCProc(
  LPVOID lpArgToCompletionRoutine   // data value
  DWORD dwTimerLowValue             // timer low value
  DWORD dwTimerHighValue            // timer high value
);

Parameters

lpArgToCompletionRoutine
[in] Specifies the value passed to the function using the lpArgToCompletionRoutine parameter of the SetWaitableTimer function.
dwTimerLowValue
[in] Specifies the low-order portion of the UTC-based time at which the timer was signaled. This value corresponds to the dwLowDateTime member of the FILETIME structure. For more information about UTC-based time, see System Time.
dwTimerHighValue
[in] Specifies the high-order portion of the UTC-based time at which the timer was signaled. This value corresponds to the dwHighDateTime member of the FILETIME structure.

Return Values

This function does not return a value.

Remarks

The completion routine is executed by the thread that activates the timer using SetWaitableTimer. However, the thread must be in an alertable state. For more information, see Asynchronous Procedure Calls.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Synchronization Overview, Synchronization Functions, FILETIME, SetWaitableTimer


TryEnterCriticalSection

The TryEnterCriticalSection function attempts to enter a critical section without blocking. If the call is successful, the calling thread takes ownership of the critical section.

BOOL TryEnterCriticalSection(
  LPCRITICAL_SECTION lpCriticalSection  // critical section
);

Parameters

lpCriticalSection
[in/out] Specifies the critical section object.

Return Values

If the critical section is successfully entered or the current thread already owns the critical section, the return value is nonzero.

If another thread already owns the critical section, the return value is zero.

Remarks

The threads of a single process can use a critical section object for mutual-exclusion synchronization. The process is responsible for allocating the memory used by a critical section object, which it can do by declaring a variable of type CRITICAL_SECTION. Before using a critical section, some thread of the process must call the InitializeCriticalSection or InitializeCriticalSectionAndSpinCount function to initialize the object.

To enable mutually exclusive use of a shared resource, each thread calls the EnterCriticalSection or TryEnterCriticalSection function to request ownership of the critical section before executing any section of code that uses the protected resource. The difference is that TryEnterCriticalSection returns immediately, regardless of whether it obtained ownership of the critical section, while EnterCriticalSection blocks until the thread can take ownership of the critical section. When it has finished executing the protected code, the thread uses the LeaveCriticalSection function to relinquish ownership, enabling another thread to become the owner and gain access to the protected resource. The thread must call LeaveCriticalSection once for each time that it entered the critical section.

Any thread of the process can use the DeleteCriticalSection function to release the system resources that were allocated when the critical section object was initialized. After this function has been called, the critical section object can no longer be used for synchronization.

If a thread terminates while it has ownership of a critical section, the state of the critical section is undefined.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, DeleteCriticalSection, EnterCriticalSection, InitializeCriticalSection, InitializeCriticalSectionAndSpinCount, LeaveCriticalSection


UnregisterWait

The UnregisterWait function cancels a registered wait operation issued by the RegisterWaitForSingleObject function.

To use a completion event, call the UnregisterWaitEx function.

BOOL UnregisterWait(
  HANDLE WaitHandle      // wait handle
);

Parameters

WaitHandle
[in] Wait handle. This handle is returned by the RegisterWaitForSingleObject function.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

UnregisterWait does not wait for all callback functions associated with the timer to complete.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, RegisterWaitForSingleObject, UnregisterWaitEx, Thread Pooling


UnregisterWaitEx

The UnregisterWaitEx function cancels a registered wait operation issued by the RegisterWaitForSingleObject function.

BOOL UnregisterWaitEx(
  HANDLE WaitHandle,      // wait handle
  HANDLE CompletionEvent  // completion event
);

Parameters

WaitHandle
[in] Wait handle. This handle is returned by the RegisterWaitForSingleObject function.
CompletionEvent
[in] Specifies an optional event to be signaled when the wait operation has been unregistered. This parameter can be NULL.

If this parameter is INVALID_HANDLE_VALUE, the function waits for all callback functions to complete before returning. Otherwise, the function returns immediately.

Return Values

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

Remarks

You cannot make a blocking call to UnregisterWaitEx from within a callback function.

After making non-blocking call, no new callback functions can be queued. However, there may be pending callback functions already queued to worker threads.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, RegisterWaitForSingleObject, Thread Pooling


WaitForMultipleObjects

The WaitForMultipleObjects function returns when one of the following occurs:

  • Either any one or all of the specified objects are in the signaled state.
  • The time-out interval elapses.

To enter an alertable wait state, use the WaitForMultipleObjectsEx function.

DWORD WaitForMultipleObjects(
  DWORD nCount,             // number of handles in array
  CONST HANDLE *lpHandles,  // object-handle array
  BOOL bWaitAll,            // wait option
  DWORD dwMilliseconds      // time-out interval
);

Parameters

nCount
[in] Specifies the number of object handles in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS.
lpHandles
[in] Pointer to an array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles to objects of different types. It may not contain the multiple copies of the same handle.

If one of these handles is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000 or later: The handles must have SYNCHRONIZE access. For more information, see Standard Access Rights.

Windows 95/98/Me: No handle may be a duplicate of another handle created using DuplicateHandle.

bWaitAll
[in] Specifies the wait type. If TRUE, the function returns when the state of all objects in the lpHandles array is signaled. If FALSE, the function returns when the state of any one of the objects is set to signaled. In the latter case, the return value indicates the object whose state caused the function to return.
dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the conditions specified by the bWaitAll parameter are not met. If dwMilliseconds is zero, the function tests the states of the specified objects and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value | Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1) | If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled. If bWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lpHandles array index of the object that satisfied the wait. If more than one object became signalled during the call, this is the array index of the signalled object with the smallest index value of all the signalled objects.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount – 1) | If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled and at least one of the objects is an abandoned mutex object. If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lpHandles array index of an abandoned mutex object that satisfied the wait.
WAIT_TIMEOUT | The time-out interval elapsed and the conditions specified by the bWaitAll parameter are not satisfied.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

The WaitForMultipleObjects function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the criteria to be met.

When bWaitAll is TRUE, the function's wait operation is completed only when the states of all objects have been set to signaled. The function does not modify the states of the specified objects until the states of all objects have been set to signaled. For example, a mutex can be signaled, but the thread does not get ownership until the states of the other objects are also set to signaled. In the meantime, some other thread may get ownership of the mutex, thereby setting its state to nonsignaled.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When bWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

The WaitForMultipleObjects function can specify handles of any of the following object types in the lpHandles array:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForMultipleObjects.

For more information, see Synchronization Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx


WaitForMultipleObjectsEx

The WaitForMultipleObjectsEx function returns when one of the following occurs:

  • Either any one or all of the specified objects are in the signaled state.
  • An I/O completion routine or asynchronous procedure call (APC) is queued to the thread.
  • The time-out interval elapses.
DWORD WaitForMultipleObjectsEx(
  DWORD nCount,             // number of handles in array
  CONST HANDLE *lpHandles,  // object-handle array
  BOOL bWaitAll,            // wait option
  DWORD dwMilliseconds,     // time-out interval
  BOOL bAlertable           // alertable option
);

Parameters

nCount
[in] Specifies the number of object handles to wait for in the array pointed to by lpHandles. The maximum number of object handles is MAXIMUM_WAIT_OBJECTS.
lpHandles
[in] Pointer to an array of object handles. For a list of the object types whose handles can be specified, see the following Remarks section. The array can contain handles of objects of different types. It may not contain the multiple copies of the same handle.

If one of these handles is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000 or later: The handles must have SYNCHRONIZE access. For more information, see Standard Access Rights.

Windows 95/98/Me: No handle may be a duplicate of another handle created using DuplicateHandle.

bWaitAll
[in] Specifies the wait type. If TRUE, the function returns when the state of all objects in the lpHandles array is set to signaled. If FALSE, the function returns when the state of any one of the objects is set to signaled. In the latter case, the return value indicates the object whose state caused the function to return.
dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the criteria specified by the bWaitAll parameter are not met and no completion routines or APCs are queued. If dwMilliseconds is zero, the function tests the states of the specified objects and checks for queued completion routines or APCs and then returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.
bAlertable
[in] Specifies whether the function returns when the system queues an I/O completion routine or APC. If TRUE, the function returns and the completion routine or APC function is executed. If FALSE, the function does not return and the completion routine or APC function is not executed.

A completion routine is queued when the ReadFileEx or WriteFileEx function in which it was specified has completed. The wait function returns and the completion routine is called only if bAlertable is TRUE and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call QueueUserAPC.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value | Meaning
WAIT_OBJECT_0 to (WAIT_OBJECT_0 + nCount – 1) | If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled. If bWaitAll is FALSE, the return value minus WAIT_OBJECT_0 indicates the lpHandles array index of the object that satisfied the wait. If more than one object became signalled during the call, this is the array index of the signalled object with the smallest index value of all the signalled objects.
WAIT_ABANDONED_0 to (WAIT_ABANDONED_0 + nCount – 1) | If bWaitAll is TRUE, the return value indicates that the state of all specified objects is signaled, and at least one of the objects is an abandoned mutex object. If bWaitAll is FALSE, the return value minus WAIT_ABANDONED_0 indicates the lpHandles array index of an abandoned mutex object that satisfied the wait.
WAIT_IO_COMPLETION | The wait was ended by one or more user-mode asynchronous procedure calls (APC) queued to the thread.
WAIT_TIMEOUT | The time-out interval elapsed, the conditions specified by the bWaitAll parameter were not satisfied, and no completion routines are queued.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

The WaitForMultipleObjectsEx function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the criteria to be met.

When bWaitAll is TRUE, the function's wait operation is completed only when the states of all objects have been set to signaled. The function does not modify the states of the specified objects until the states of all objects have been set to signaled. For example, a mutex can be signaled, but the thread does not get ownership until the states of the other objects are also set to signaled. In the meantime, some other thread may get ownership of the mutex, thereby setting its state to nonsignaled.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one. When bWaitAll is FALSE, and multiple objects are in the signaled state, the function chooses one of the objects to satisfy the wait; the states of the objects not selected are unaffected.

The WaitForMultipleObjectsEx function can specify handles of any of the following object types in the lpHandles array:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForMultipleObjectsEx.

For more information, see Reading, Writing, and Locking Files.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx


WaitForSingleObject

The WaitForSingleObject function returns when one of the following occurs:

  • The specified object is in the signaled state.
  • The time-out interval elapses.

To enter an alertable wait state, use the WaitForSingleObjectEx function. To wait for multiple objects, use the WaitForMultipleObjects.

DWORD WaitForSingleObject(
  HANDLE hHandle,        // handle to object
  DWORD dwMilliseconds   // time-out interval
);

Parameters

hHandle
[in] Handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.

If this handle is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000 or later: The handle must have SYNCHRONIZE access. For more information, see Standard Access Rights.

dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If dwMilliseconds is zero, the function tests the object's state and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value | Meaning
WAIT_ABANDONED | The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_OBJECT_0 | The state of the specified object is signaled.
WAIT_TIMEOUT | The time-out interval elapsed, and the object's state is nonsignaled.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters the wait state. It uses no processor time while waiting for the object state to become signaled or the time-out interval to elapse.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one.

The WaitForSingleObject function can wait for the following objects:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.

For more information, see Using Mutex Objects.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx, WaitForMultipleObjects, WaitForSingleObjectEx


WaitForSingleObjectEx

The WaitForSingleObjectEx function returns when one of the following occurs:

  • The specified object is in the signaled state.
  • An I/O completion routine or asynchronous procedure call (APC) is queued to the thread.
  • The time-out interval elapses.

To wait for multiple objects, use the WaitForMultipleObjectsEx.

DWORD WaitForSingleObjectEx(
  HANDLE hHandle,        // handle to object
  DWORD dwMilliseconds,  // time-out interval
  BOOL bAlertable        // alertable option
);

Parameters

hHandle
[in] Handle to the object. For a list of the object types whose handles can be specified, see the following Remarks section.

If this handle is closed while the wait is still pending, the function's behavior is undefined.

Windows NT/2000 or later: The handle must have SYNCHRONIZE access. For more information, see Standard Access Rights.

dwMilliseconds
[in] Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled and no completion routines or APCs are queued. If dwMilliseconds is zero, the function tests the object's state and checks for queued completion routines or APCs and then returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.
bAlertable
[in] Specifies whether the function returns when the system queues an I/O completion routine or APC. If TRUE, the function returns and the completion routine or APC function is executed. If FALSE, the function does not return, and the completion routine or APC function is not executed.

A completion routine is queued when the ReadFileEx or WriteFileEx function in which it was specified has completed. The wait function returns and the completion routine is called only if bAlertable is TRUE, and the calling thread is the thread that initiated the read or write operation. An APC is queued when you call QueueUserAPC.

Return Values

If the function succeeds, the return value indicates the event that caused the function to return. This value can be one of the following.

Value | Meaning
WAIT_OBJECT_0 | The state of the specified object is signaled.
WAIT_ABANDONED | The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_IO_COMPLETION | The wait was ended by one or more user-mode asynchronous procedure calls (APC) queued to the thread.
WAIT_TIMEOUT | The time-out interval elapsed, and the object's state is nonsignaled.

If the function fails, the return value is WAIT_FAILED. To get extended error information, call GetLastError.

Remarks

The WaitForSingleObjectEx function determines whether the wait criteria have been met. If the criteria have not been met, the calling thread enters the wait state. It uses no processor time while waiting for the criteria to be met.

The function modifies the state of some types of synchronization objects. Modification occurs only for the object whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one.

The WaitForSingleObjectEx function can wait for the following objects:

  • Change notification
  • Console input
  • Event
  • Job
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and COM CoInitialize. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObjectEx.

For an example, see Named Pipe Server Using Completion Routines.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.
Library: Use Kernel32.lib.

See Also

Synchronization Overview, Synchronization Functions, MsgWaitForMultipleObjects, MsgWaitForMultipleObjectsEx, WaitForMultipleObjectsEx


WaitOrTimerCallback

The WaitOrTimerCallback function is an application-defined function that serves as the starting address for a timer callback or a registered wait callback. Specify this address when calling the CreateTimerQueueTimer, RegisterWaitForSingleObject function.

The WAITORTIMERCALLBACK type defines a pointer to this callback function. WaitOrTimerCallback is a placeholder for the application-defined function name.

VOID CALLBACK WaitOrTimerCallback(
  PVOID lpParameter,        // thread data
  BOOLEAN TimerOrWaitFired  // reason
);

Parameters

lpParameter
[in] Receives the thread data passed to the function using a parameter of the CreateTimerQueueTimer or RegisterWaitForSingleObject function.
TimerOrWaitFired
[in] If this parameter is TRUE, the wait timed out. If this parameter is FALSE, the wait event has been signaled. (This parameter is always TRUE for timer callbacks.)

Return Values

This function does not return a value.

Remarks

This callback function must not call the TerminateThread function.

Example

For an example that uses this callback function, see Using Timer Queues.

Requirements

Windows NT/2000 or later: Requires Windows 2000 or later.
Windows 95/98/Me: Unsupported.
Header: Declared in Winbase.h; include Windows.h.

See Also

Synchronization Overview, Synchronization Functions, CreateTimerQueueTimer, RegisterWaitForSingleObject


Synchronization Structures

The following structure is used with synchronization.

OVERLAPPED


OVERLAPPED

The OVERLAPPED structure contains information used in asynchronous input and output (I/O).

typedef struct _OVERLAPPED {
    ULONG_PTR  Internal;
    ULONG_PTR  InternalHigh;
    DWORD  Offset;
    DWORD  OffsetHigh;
    HANDLE hEvent;
} OVERLAPPED;

Members

Internal
Reserved for operating system use. This member, which specifies a system-dependent status, is valid when the GetOverlappedResult function returns without setting the extended error information to ERROR_IO_PENDING.
InternalHigh
Reserved for operating system use. This member, which specifies the length of the data transferred, is valid when the GetOverlappedResult function returns TRUE.
Offset
Specifies a file position at which to start the transfer. The file position is a byte offset from the start of the file. The calling process sets this member before calling the ReadFile or WriteFile function. This member is ignored when reading from or writing to named pipes and communications devices and should be zero.
OffsetHigh
Specifies the high word of the byte offset at which to start the transfer. This member is ignored when reading from or writing to named pipes and communications devices and should be zero.
hEvent
Handle to an event set to the signaled state when the operation has been completed. The calling process must set this member either to zero or a valid event handle before calling any overlapped functions. To create an event object, use the CreateEvent function.

Remarks

You can use the HasOverlappedIoCompleted macro to determine whether an asynchronous I/O operation has completed. You can use the CancelIo function to cancel an asynchronous I/O operation.

Requirements

Windows NT/2000 or later: Requires Windows NT 3.1 or later.
Windows 95/98/Me: Requires Windows 95 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Synchronization Overview, Synchronization Structures, CancelIo, GetOverlappedResult, HasOverlappedIoCompleted, ReadFile, WriteFile


Synchronization Macros

The following macro is used with synchronization.

HasOverlappedIoCompleted


HasOverlappedIoCompleted

The HasOverlappedIoCompleted macro provides a high performance test operation that can be used to poll for the completion of an outstanding I/O operation.

BOOL HasOverlappedIoCompleted(
  LPOVERLAPPED lpOverlapped
);

Parameters

lpOverlapped
Pointer to an OVERLAPPED structure that was specified when the overlapped I/O operation was started.

Return Values

Returns TRUE if the I/O operation has completed, and FALSE otherwise.

Remarks

Do not call this macro unless the call to GetLastError returns ERROR_IO_PENDING, indicating that the overlapped I/O has started.

To cancel all pending asynchronous I/O operations, use the CancelIo function. This function only cancels operations issued by the calling thread for the specified file handle. I/O operations that are canceled complete with the error ERROR_OPERATION_ABORTED.

To get more details about a completed I/O operation, call the GetOverlappedResult or GetQueuedCompletionStatus function.

Requirements

Windows NT/2000 or later: Requires Windows NT 4.0 or later.
Windows 95/98/Me: Requires Windows 98 or later.
Header: Declared in Winbase.h; include Windows.h.

See Also

Synchronization Overview, Synchronization Macros, CancelIo, ConnectNamedPipe, DeviceIoControl, OVERLAPPED, ReadFile, TransactNamedPipe, WaitCommEvent, WriteFile


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    Remedy: Insert the MSDN Library CD into the CD-ROM drive.