| Previous | Main | Next | Site Index | Download | Disclaimer | Privacy |


 

 

 

 

 

 

WINDOWS PROGRAMMING: VARIOUS SUPPLEMENTARY NOTE

 

 

 

 

 

 

 

 

Windows Service: Functions used in program examples of Windows Processes & threads 1 and Windows Processes & threads 2 wherever applicable. To learn about function you can jump to C & C++ functions tutorial.

 

 

The Page Index

  1. CreateThread()

  2. CreateEvent()

  3. SetEvent()

  4. OutputDebugString()

  5. FormatMessage()

  6. ZeroMemory()

  7. lstrcat()

  8. LocalFree()

  9. OpenSCManager()

  10. CreateService()

 

 

 

 

 

 

 

 

 

 

 

 

 

CreateThread()

 

Item

Description

Function

CreateThread().

Use

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.

Prototype

HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );

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.

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. The ACLs in the default security descriptor for a thread come from the primary or impersonation token of the creator.

dwStackSize - [in] Initial size of the stack, in bytes. The system rounds this value to the nearest page. If this parameter is zero, the new thread uses the default size for the executable.

lpStartAddress - [in] Pointer to the application-defined function to be executed by the thread and represents the starting address of the thread.

lpParameter - [in] Pointer to a variable to be passed to the thread.

dwCreationFlags - [in] 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. If the STACK_SIZE_PARAM_IS_A_RESERVATION flag is specified, the dwStackSize parameter specifies the initial reserve size of the stack. Otherwise, dwStackSize specifies the commit size. Windows 2000/NT and Windows Me/98/95:  The STACK_SIZE_PARAM_IS_A_RESERVATION flag is not supported.

lpThreadId - [out] Pointer to a variable that receives the thread identifier. If this parameter is NULL, the thread identifier is not returned. For Windows Me/98/95:  This parameter may not be NULL.

Return value

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). For Windows Me/98/95:  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.

Include file

<windows.h>

Remark

See below.

 

Table 1.

 

Some 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 the THREAD_ALL_ACCESS access right. 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. 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:

Do not create a thread while impersonating another user. The call will succeed, however the newly created thread will have reduced access rights to itself when calling GetCurrentThread(). The access rights granted are derived from the access rights that the impersonated user has to the process. Some access rights including THREAD_SET_THREAD_TOKEN and THREAD_GET_CONTEXT may not be present, leading to unexpected failures.

  1. 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.

  2. Only one thread in a process can be in a DLL initialization or detach routine at a time.

  3. ExitProcess() does not return until no threads are in their DLL initialization or detach routines.

A thread in an executable that is linked to the static C run-time library (CRT) should use _beginthread() and _endthread() for thread management rather than CreateThread() and ExitThread(). Failure to do so results in small memory leaks when the thread calls ExitThread(). Another work around is to link the executable to the CRT in a DLL instead of the static CRT. Note that this memory leak only occurs from a DLL if the DLL is linked to the static CRT and a thread calls the DisableThreadLibraryCalls() function. Otherwise, it is safe to call CreateThread() and ExitThread() from a thread in a DLL that links to the static CRT.

 

CreateEvent()

 

Item

Description

Function

CreateEvent().

Use

Creates or opens a named or unnamed event object.

Prototype

HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCTSTR lpName);

Parameters

See below.

Return value

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().

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode. More remarks below.

 

Table 2.

 

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. 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. The ACLs in the default security descriptor for an event come from the primary or impersonation token of the creator.

bManualReset - [in] If this parameter is TRUE, the function creates a manual-reset event object which requires use of the ResetEvent() function set the state to non-signaled. If this parameter is FALSE, the function creates an auto-reset event object, and system automatically resets the state to non-signaled after a single waiting thread has been released.

bInitialState - [in] If this parameter is TRUE, the initial state of the event object is signaled; otherwise, it is non-signaled.

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 the EVENT_ALL_ACCESS access right. 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 (\). Windows XP Home Edition:  Fast user switching is implemented using Terminal Services sessions. The first user to log on uses session 0, the next user to log on uses session 1, and so on. Kernel object names must follow the guidelines outlined for Terminal Services so that applications can support multiple users. Windows 2000:  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 Me/98/95:  The name can contain any character except the backslash character. The empty string ("") is a valid object name.

 

Some Notes

 

The handle returned by CreateEvent() has the EVENT_ALL_ACCESS access right 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 non-signaled. When the state of a manual-reset event object is signaled, it remains signaled until it is explicitly reset to non-signaled 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 non-signaled. 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. Windows Me/98/95:  CreateEventW() is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows Me/98/95 Systems.

 

SetEvent()

 

Item

Description

Function

SetEvent().

Use

Sets the specified event object to the signaled state.

Prototype

BOOL SetEvent(HANDLE hEvent);

Parameters

hEvent - [in] Handle to the event object. The CreateEvent() or OpenEvent() function returns this handle. The handle must have the EVENT_MODIFY_STATE access right.

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().

Include file

<windows.h>

Remark

The state of a manual-reset event object remains signaled until it is set explicitly to the non-signaled 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 non-signaled. If no threads are waiting, the event object's state remains signaled. Setting an event that is already set has no effect.

 

Table 3.

 

OutputDebugString()

 

Item

Description

Function

OutputDebugString().

Use

Sends a string to the debugger for display.

Prototype

void OutputDebugString(LPCTSTR lpOutputString);

Parameters

lpOutputString - [in] Pointer to the null-terminated string to be displayed.

Return value

This function does not return a value.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode. If the application has no debugger, the system debugger displays the string. If the application has no debugger and the system debugger is not active, OutputDebugString() does nothing. For Windows Me/98/95:  OutputDebugStringW() is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows Me/98/95 Systems.

 

Table 4.

 

FormatMessage()

 

Item

Description

Function

FormatMessage().

Use

Formats a message string. The function requires a message definition as input. The message definition can come from a buffer passed into the function. It can come from a message table resource in an already-loaded module. Or the caller can ask the function to search the system's message table resource(s) for the message definition. The function finds the message definition in a message table resource based on a message identifier and a language identifier. The function copies the formatted message text to an output buffer, processing any embedded insert sequences if requested.

Prototype

DWORD FormatMessage( DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize, va_list* Arguments);

Parameters

See below.

Return value

If the function succeeds, the return value is the number of TCHARs stored in the output buffer, excluding the terminating null character. If the function fails, the return value is zero. To get extended error information, call GetLastError().

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. Note that Unicode support on Windows Me/98/95 requires Microsoft Layer for Unicode. More remarks below.

 

Table 5.

 

Parameters

 

dwFlags - [in] Formatting options, and how to interpret the lpSource parameter. The low-order byte of dwFlags specifies how the function handles line breaks in the output buffer. The low-order byte can also specify the maximum width of a formatted output line. This parameter can be one or more of the following values.

 

Value

Meaning

FORMAT_MESSAGE_ALLOCATE_BUFFER

The lpBuffer parameter is a pointer to a PVOID pointer, and that the nSize parameter specifies the minimum number of TCHARs to allocate for an output message buffer. The function allocates a buffer large enough to hold the formatted message, and places a pointer to the allocated buffer at the address specified by lpBuffer. The caller should use the LocalFree() function to free the buffer when it is no longer needed.

FORMAT_MESSAGE_IGNORE_INSERTS

Insert sequences in the message definition are to be ignored and passed through to the output buffer unchanged. This flag is useful for fetching a message for later formatting. If this flag is set, the Arguments parameter is ignored.

FORMAT_MESSAGE_FROM_STRING

The lpSource parameter is a pointer to a null-terminated message definition. The message definition may contain insert sequences, just as the message text in a message table resource may. Cannot be used with FORMAT_MESSAGE_FROM_HMODULE or FORMAT_MESSAGE_FROM_SYSTEM.

FORMAT_MESSAGE_FROM_HMODULE

The lpSource parameter is a module handle containing the message-table resource(s) to search. If this lpSource handle is NULL, the current process's application image file will be searched. Cannot be used with FORMAT_MESSAGE_FROM_STRING.

FORMAT_MESSAGE_FROM_SYSTEM

The function should search the system message-table resource(s) for the requested message. If this flag is specified with FORMAT_MESSAGE_FROM_HMODULE, the function searches the system message table if the message is not found in the module specified by lpSource. Cannot be used with FORMAT_MESSAGE_FROM_STRING. If this flag is specified, an application can pass the result of the GetLastError() function to retrieve the message text for a system-defined error.

FORMAT_MESSAGE_ARGUMENT_ARRAY

The Arguments parameter is not a va_list structure, but is a pointer to an array of values that represent the arguments. This flag cannot be used with 64-bit argument values. If you are using 64-bit values, you must use the va_list structure.

 

Table 6

 

The low-order byte of dwFlags can specify the maximum width of a formatted output line. Use the FORMAT_MESSAGE_MAX_WIDTH_MASK constant and bitwise Boolean operations to set and retrieve this maximum width value. The following table shows how FormatMessage() interprets the value of the low-order byte.

 

Value

Meaning

0

There are no output line width restrictions. The function stores line breaks that are in the message definition text into the output buffer.

A nonzero value other than FORMAT_MESSAGE_MAX_WIDTH_MASK

The nonzero value is the maximum number of characters in an output line. The function ignores regular line breaks in the message definition text. The function never splits a string delimited by white space across a line break. The function stores hard-coded line breaks in the message definition text into the output buffer. Hard-coded line breaks are coded with the %n escape sequence.

FORMAT_MESSAGE_MAX_WIDTH_MASK

The function ignores regular line breaks in the message definition text. The function stores hard-coded line breaks in the message definition text into the output buffer. The function generates no new line breaks.

 

Table 7

 

lpSource - [in] Location of the message definition. The type of this parameter depends upon the settings in the dwFlags parameter.

 

dwFlags Setting

Meaning

FORMAT_MESSAGE_FROM_HMODULE

Handle to the module that contains the message table to search.

FORMAT_MESSAGE_FROM_STRING

Pointer to a string that consists of unformatted message text. It will be scanned for inserts and formatted accordingly.

 

Table 8

 

If neither of these flags is set in dwFlags, then lpSource is ignored.

dwMessageId - [in] Message identifier for the requested message. This parameter is ignored if dwFlags includes FORMAT_MESSAGE_FROM_STRING.

dwLanguageId - [in] Language identifier for the requested message. This parameter is ignored if dwFlags includes FORMAT_MESSAGE_FROM_STRING. If you pass a specific LANGID in this parameter, FormatMessage() will return a message for that LANGID only. If the function cannot find a message for that LANGID, it returns ERROR_RESOURCE_LANG_NOT_FOUND. If you pass in zero, FormatMessage() looks for a message for LANGIDs in the following order:

 

  1. Language neutral.

  2. Thread LANGID, based on the thread's locale value.

  3. User default LANGID, based on the user's default locale value.

  4. System default LANGID, based on the system default locale value.

  5. US English.

 

If FormatMessage() does not locate a message for any of the preceding LANGIDs, it returns any language message string that is present. If that fails, it returns ERROR_RESOURCE_LANG_NOT_FOUND.

lpBuffer - [out] Pointer to a buffer that receives the null-terminated string that specifies the formatted message. If dwFlags includes FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using the LocalAlloc() function, and places the pointer to the buffer at the address specified in lpBuffer. This buffer cannot be larger than 64K bytes.

nSize - [in] If the FORMAT_MESSAGE_ALLOCATE_BUFFER flag is not set, this parameter specifies the size of the output buffer, in TCHARs. If FORMAT_MESSAGE_ALLOCATE_BUFFER is set, this parameter specifies the minimum number of TCHARs to allocate for an output buffer. The output buffer cannot be larger than 64K bytes.

Arguments - [in] Pointer to an array of values that are used as insert values in the formatted message. A %1 in the format string indicates the first value in the Arguments array; a %2 indicates the second argument; and so on. The interpretation of each value depends on the formatting information associated with the insert in the message definition. The default is to treat each value as a pointer to a null-terminated string. By default, the Arguments parameter is of type va_list*, which is a language- and implementation-specific data type for describing a variable number of arguments. The state of the va_list argument is undefined upon return from the function. If the caller is to use the va_list again, it must destroy the variable argument list pointer using va_begin and reinitialize it with va_start. If you do not have a pointer of type va_list*, then specify the FORMAT_MESSAGE_ARGUMENT_ARRAY flag and pass a pointer to an array of DWORD_PTR values; those values are input to the message formatted as the insert values. Each insert must have a corresponding element in the array. For Windows Me/98/95:  No single insertion string may exceed 1023 characters in length.

 

Some Remarks

 

Within the message text, several escape sequences are supported for dynamically formatting the message. These escape sequences and their meanings are shown in the following table. All escape sequences start with the percent character (%).

 

Escape Sequence

Meaning

%0

Terminates a message text line without a trailing new line character. This escape sequence can be used to build up long lines or to terminate the message itself without a trailing new line character. It is useful for prompt messages.

%n!format string!

Identifies an insert. The value of n can be in the range 1 through 99. The format string (which must be bracketed by exclamation marks) is optional and defaults to !s! if not specified. The format string can contain the * specifier for either the precision or the width component. If * is specified for one component, the FormatMessage() function uses insert %n+1; it uses %n+2 if * is specified for both components. Floating-point format specifiers: e, E, f, and g are not supported. The workaround is to use the wsprintf() function to format the floating-point number into a temporary buffer, and then use that buffer as the insert string. Inserts that use the I64 prefix are treated as two 32-bit arguments. They must be used before subsequent arguments are used. So this string is OK:

 

%1!d! %2!I64X! %3!d!

 

but this string is not:

 

%3!d! %1!I64X! %2!d!

 

Table 9

 

Any other nondigit character following a percent character is formatted in the output message without the percent character. Following are some examples.

 

Format string

Resulting output

%%

A single percent sign in the formatted message text.

%n

A hard line break when the format string occurs at the end of a line. This format string is useful when FormatMessage() is supplying regular line breaks so the message fits in a certain width.

%space

A space in the formatted message text. This format string can be used to ensure the appropriate number of trailing spaces in a message text line.

%.

A single period in the formatted message text. This format string can be used to include a single period at the beginning of a line without terminating the message text definition.

%!

A single exclamation point in the formatted message text. This format string can be used to include an exclamation point immediately after an insert without its being mistaken for the beginning of a printf format string.

 

Table 10

 

For Windows Me/98/95:  FormatMessageW() is supported by the Microsoft Layer for Unicode. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows Me/98/95 Systems.

 

Example Code

 

The FormatMessage() function can be used to obtain error message strings for the system error codes returned by GetLastError(), as shown in the following sample code.

// For WinXp

#define _WIN32_WINNT 0x0501

#include <windows.h>

#include <stdio.h>

 

int main()

{

       // Message buffer...

       LPVOID lpMsgBuf;

if (!FormatMessage(

    FORMAT_MESSAGE_ALLOCATE_BUFFER |

    FORMAT_MESSAGE_FROM_SYSTEM |

    FORMAT_MESSAGE_IGNORE_INSERTS,

    NULL,

    GetLastError(),

    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language

    (LPTSTR) &lpMsgBuf,

    0,

    NULL))

{

    // Handle the error.

    printf("FormatMessage() failed! error code: %d.\n", GetLastError());

    return 1;

}

else

// Process any inserts in lpMsgBuf.

printf("Processing lpMsgBuf...\n");

// ...

// Display the string by using message box...just dummy here…

MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error Message", MB_OK | MB_ICONINFORMATION);

// Free the buffer.

LocalFree(lpMsgBuf);

return 0;

}

 

FormatMessage() skeleton program example

 

FormatMessage() skeleton program example: message box

 

Another example: Looking Up Text for Error Code Numbers

 

On Windows Server 2003 family, Windows XP, Windows 2000, and Windows NT, it is sometimes necessary to display error text associated with error codes returned from networking-related functions. You may need to perform this task with the network management functions provided by the system. The error text for these messages is found in the message table file named Netmsg.dll, which is found in %systemroot%\system32. This file contains error messages in the range NERR_BASE (2100) through MAX_NERR(NERR_BASE+899). These error codes are defined in the SDK header file lmerr.h. The LoadLibrary() and LoadLibraryEx() functions can load netmsg.dll. The FormatMessage() function maps an error code to message text, given a module handle to the netmsg.dll file. The following sample illustrates how to display error text associated with network management functions, in addition to displaying error text associated with system-related error codes. If the supplied error number is in a specific range, the netmsg.dll message module is loaded and used to look up the specified error number with the FormatMessage() function.

// For WinXp

#define _WIN32_WINNT 0x0501

#include <windows.h>

#include <stdio.h>

#include <lmerr.h>

 

void DisplayErrorText(DWORD dwLastError);

 

#define RTN_OK 0

#define RTN_USAGE 1

#define RTN_ERROR 13

 

int __cdecl main(int argc, char *argv[])

{

    if (argc != 2)

       {

        fprintf(stderr, "Usage: %s <error number>.\n", argv[0]);

        return RTN_USAGE;

    }

    DisplayErrorText(atoi(argv[1]));

    return RTN_OK;

}

void DisplayErrorText(DWORD dwLastError)

{

    HMODULE hModule = NULL; // default to system source

    LPSTR MessageBuffer;

    DWORD dwBufferLength;

    DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;

    // If dwLastError is in the network range, load the message source...

    if(dwLastError >= NERR_BASE && dwLastError <= MAX_NERR)

       {

        hModule = LoadLibraryEx(

            TEXT("netmsg.dll"),

            NULL,

            LOAD_LIBRARY_AS_DATAFILE  );

        if(hModule != NULL)

            dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;

    }

    // Call FormatMessage() to allow for message text to be acquired from the system or from the supplied module handle.

    if(dwBufferLength = FormatMessageA(

        dwFormatFlags,

        hModule, // module to get message from (NULL == system)

        dwLastError,

        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language

        (LPSTR) &MessageBuffer,

        0,

        NULL

        ))

    {

        DWORD dwBytesWritten;

        // Output message string on stderr.

        WriteFile(

            GetStdHandle(STD_ERROR_HANDLE),

            MessageBuffer,

            dwBufferLength,

            &dwBytesWritten,

            NULL

            );

        // Free the buffer allocated by the system.

        LocalFree(MessageBuffer);

    }

    // If we loaded a message source, unload it.

    if (hModule != NULL)

        FreeLibrary(hModule);

}

 

After you compile this program, you can insert the error code number as an argument and the program will display the text. For example:

 

Microsoft Windows XP [Version 5.1.2600]

(C) Copyright 1985-2001 Microsoft Corp.

 

F:\myproject\myprocess\Debug>myprocess

Usage: myprocess <error number>.

 

F:\myproject\myprocess\Debug>myprocess 1234

No service is operating at the destination network endpoint on the remote system.

 

F:\myproject\myprocess\Debug>myprocess 2

The system cannot find the file specified.

 

F:\myproject\myprocess\Debug>myprocess 156

The recipient process has refused the signal.

 

F:\myproject\myprocess\Debug>myprocess 0

The operation completed successfully.

 

F:\myproject\myprocess\Debug>myprocess 5

Access is denied.

 

F:\myproject\myprocess\Debug>

 

ZeroMemory()

 

Item

Description

Function

ZeroMemory().

Use

A macro that fills a block of memory with zeros. To avoid undesired effects of optimizing compilers, use the SecureZeroMemory() function.

Prototype

void ZeroMemory(PVOID Destination, SIZE_T Length);

Parameters

Destination - [in] Pointer to the starting address of the block of memory to fill with zeros.

Length - [in] Size of the block of memory to fill with zeros, in bytes.

Return value

This function has no return value.

Include file

<windows.h>

Remark

This function is defined as the RtlZeroMemory() macro.

 

Table 11.

 

lstrcat()

 

Item

Description

Function

lstrcat().

Use

Appends one string to another.

Prototype

LPTSTR lstrcat(LPTSTR lpString1, LPTSTR lpString2);

Parameters

lpString1 - [in, out] Pointer to a null-terminated string. The buffer must be large enough to contain both strings.

lpString2 - [in] Pointer to the null-terminated string to be appended to the string specified in the lpString1 parameter.

Return value

If the function succeeds, the return value is a pointer to the buffer. If the function fails, the return value is NULL.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions on Windows NT, Windows 2000, Windows XP. More remarks below.

 

Table 12.

 

Security Alert: Using this function incorrectly can compromise the security of your application. The first argument, lpString1, must be large enough to hold lpString2 and the closing '\0', otherwise a buffer overrun may occur. Buffer overruns may lead to a denial of service attack against the application if an access violation occurs. In the worst case, a buffer overrun may allow an attacker to inject executable code into your process, especially if lpString1 is a stack-based buffer.

Consider using one of the following alternatives: StringCbCat(), StringCbCatEx(), StringCbCatN(), StringCbCatNEx(), StringCchCat(), StringCchCatEx(), StringCchCatN(), or StringCchCatNEx(). For Windows 95/98/Me: lstrcatW() is supported by the Microsoft® Layer for Unicode (MSLU). Although the W version already exists on Microsoft Windows® 98/Me, it is included to give more consistent behavior across all Windows operating systems. To use this, you must add certain files to your application, as outlined in Microsoft Layer for Unicode on Windows 95/98/Me Systems.

 

LocalFree()

 

Item

Description

Function

LocalFree().

Use

Frees the specified local memory object and invalidates its handle.

Note that the local functions are slower than other memory management functions and do not provide as many features. Therefore, new applications should use the heap functions.

Prototype

HLOCAL LocalFree(HLOCAL hMem);

Parameters

hMem - [in] Handle to the local memory object. This handle is returned by either the LocalAlloc() or LocalReAlloc() function.

Return value

If the function succeeds, the return value is NULL. If the function fails, the return value is equal to a handle to the local memory object. To get extended error information, call GetLastError().

Include file

<windows.h>

Remark

If the process tries to examine or modify the memory after it has been freed, heap corruption may occur or an access violation exception (EXCEPTION_ACCESS_VIOLATION) may be generated. If the hMem parameter is NULL, LocalFree() ignores the parameter and returns NULL.

The LocalFree() function will free a locked memory object. A locked memory object has a lock count greater than zero. The LocalLock() function locks a local memory object and increments the lock count by one. The LocalUnlock() function unlocks it and decrements the lock count by one. To get the lock count of a local memory object, use the LocalFlags() function.

If an application is running under a debug version of the system, LocalFree() will issue a message that tells you that a locked object is being freed. If you are debugging the application, LocalFree() will enter a breakpoint just before freeing a locked object. This allows you to verify the intended behavior, and then continue execution.

 

Table 13.

 

OpenSCManager()

 

Item

Description

Function

OpenSCManager().

Use

Establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.

Prototype

SC_HANDLE OpenSCManager( LPCTSTR lpMachineName, LPCTSTR lpDatabaseName, DWORD dwDesiredAccess);

Parameters

lpMachineName - [in] Pointer to a null-terminated string that specifies the name of the target computer. 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] Access to the service control manager. Before granting the requested access rights, 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 right is implicitly specified by calling this function.

Return value

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.

  1. ERROR_ACCESS_DENIED - The requested access was denied.

  2. ERROR_DATABASE_DOES_NOT_EXIST - The specified database does not exist.

  3. ERROR_INVALID_PARAMETER - A specified parameter is invalid.

Include file

<windows.h>

Remark

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. Only authenticated users are granted the SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access rights. Windows 2000/NT:  All processes are granted the SC_MANAGER_CONNECT, SC_MANAGER_ENUMERATE_SERVICE, and SC_MANAGER_QUERY_LOCK_STATUS access rights. 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 that can be 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. Implemented as Unicode and ANSI versions.

 

Table 14.

 

CreateService()

 

Item

Description

Function

CreateService().

Use

Creates a service object and adds it to the specified service control manager database.

Prototype

SC_HANDLE CreateService( SC_HANDLE hSCManager, LPCTSTR lpServiceName, LPCTSTR lpDisplayName, DWORD dwDesiredAccess, DWORD dwServiceType, DWORD dwStartType, DWORD dwErrorControl, LPCTSTR lpBinaryPathName, LPCTSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCTSTR lpDependencies, LPCTSTR lpServiceStartName, LPCTSTR lpPassword );

Parameters

See below.

Return value

See below.

Include file

<windows.h>

Remark

Implemented as Unicode and ANSI versions. More remarks below.

 

Table 15.

 

Parameters

 

hSCManager - [in] Handle to the service control manager database. This handle is returned by the OpenSCManager() function and must have the SC_MANAGER_CREATE_SERVICE access right.

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] Access to the service. Before granting the requested access, the system checks the access token of the calling process.

dwServiceType - [in] Service types. This parameter can be one of the following values.

 

Type

Meaning

SERVICE_FILE_SYSTEM_DRIVER

File system driver service.

SERVICE_KERNEL_DRIVER

Driver service.

SERVICE_WIN32_OWN_PROCESS

Service that runs in its own process.

SERVICE_WIN32_SHARE_PROCESS

Service that shares a process with one or more other services.

 

Table 16

 

If you specify either SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS, and the service is running in the context of the LocalSystem account, you can also specify the following type.

 

Type

Meaning

SERVICE_INTERACTIVE_PROCESS

The service can interact with the desktop.

 

Table 17

 

dwStartType - [in] Service start options. This parameter can be one of the following values.

 

Type

Meaning

SERVICE_AUTO_START

A service started automatically by the service control manager during system startup.

SERVICE_BOOT_START

A device driver started by the system loader. This value is valid only for driver services.

SERVICE_DEMAND_START

A service started by the service control manager when a process calls the StartService() function.

SERVICE_DISABLED

A service that cannot be started. Attempts to start the service result in the error code ERROR_SERVICE_DISABLED.

SERVICE_SYSTEM_START

A device driver started by the IoInitSystem() function. This value is valid only for driver services.

 

Table 18

 

dwErrorControl - [in] Severity of the error, and action taken, if this service fails to start. This parameter can 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.

 

Table 19

 

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\"".

 

The path can also include arguments for an auto-start service. For example:

 

"d:\\myshare\\myservice.exe arg1 arg2"

 

These arguments are passed to the service entry point (typically the main function).

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. The startup program uses load ordering groups to load groups of services in a specified order with respect to the other groups. The list of load ordering groups is contained in the following registry value:

 

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ServiceGroupOrder

 

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 following registry value:

 

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\GroupOrderList

 

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 name of the account under which the service should run. 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. If the service type specifies SERVICE_INTERACTIVE_PROCESS, the service must run in the LocalSystem account. If this parameter is NT AUTHORITY\LocalService, CreateService() uses the LocalService account. If the parameter is NT AUTHORITY\NetworkService, CreateService() uses the NetworkService account. Windows NT:  If the service type is SERVICE_WIN32_SHARE_PROCESS, you must specify the LocalSystem account. On later versions of Windows, 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.

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 or if the service runs in the LocalService, NetworkService, or LocalSystem account.

 

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.

 

Return code

Description

ERROR_ACCESS_DENIED

The handle to the SCM database does not have the SC_MANAGER_CREATE_SERVICE access right.

ERROR_CIRCULAR_DEPENDENCY

A circular service dependency was specified.

ERROR_DUPLICATE_SERVICE_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.

 

Table 20

 

Some 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 by CreateService(), ChangeServiceConfig(), and ChangeServiceConfig2() is saved as values under this key. The following are examples of values stored for a service.

 

Value

Description

DependOnGroup

Load-ordering groups on which this service depends, as specified by lpDependencies.

DependOnService

Services on which this service depends, as specified by lpDependencies.

Description

Description specified by ChangeServiceConfig2().

DisplayName

Display name specified by lpDisplayName.

ErrorControl

Error control specified by dwErrorControl.

FailureActions

Failure actions specified by ChangeServiceConfig2().

Group

Load ordering group specified by lpLoadOrderGroup. Note that setting this value can override the setting of the DependOnService value.

ImagePath

Name of binary file, as specified by lpBinaryPathName.

ObjectName

Account name specified by lpServiceStartName.

Start

When to start service, as specified by dwStartType.

Tag

Tag identifier specified by lpdwTagId.

Type

Service type specified by dwServiceType.

 

Table 21

 

Setup programs and the service itself can create additional subkeys for service-specific information.

The returned handle is only valid for the process that called CreateService(). It can be closed by calling the CloseServiceHandle() function. If you are creating services that share a process, avoid calling functions with process-wide effects, such as ExitProcess(). In addition, do not unload your service DLL.

 

-----------------------------------------------------------Part 2/4------------------------------------------------------------

 

 

 

 

 

Further reading and digging:

 

  1. Microsoft Visual C++, online MSDN.

  2. Structure, enum, union and typedef story can be found at C enum, typedef, define etc..

  3. For Multibytes, Unicode characters and Localization please refer to Unicode & Multibyte 1 (Story) and Unicode & Multibyte 2 (Implementation).

  4. Windows data type information is in Windows data type.

  5. Check the best selling C / C++ and Windows books at Amazon.com.

 

 

 

 

 

 

 

| Previous | Main | Next | Site Index | Download | Disclaimer | Privacy |