25    Security Support Provider Interface

The Security Support Provider Interface (SSPI) provides a common interface between transport-level applications and security providers. SSPI provides a mechanism by which a distributed application can call one of several security providers to obtain an authenticated connection without knowledge of the details of the security protocol.

The SSPI consists of the following APIs:

SSPI does not currently provide any public interfaces for encryption/decryption functionality. Future versions of the SSPI will make message support routines for encryption available.

A security provider is a dynamic-link library that implements the Security Support Provider Interface and makes one or more security packages available to applications. A security package maps the SSPI functions to an implementation of the security protocol specific to that package, such as NTLM, Kerberos, or SSL. Security packages are sometimes referred to as ``SSPs,'' such as the ``NTLM SSP.'' The name of the security package is used in the initialization step to identify a specific package.

The Security Support Provider Interface allows an application to use any of the available security packages on a system without changing the interface to use security services. SSPI does not establish logon credentials because that is generally a privileged operation handled by the operating system.

An application can use the package management functions to list the security packages available and select one to support its needs. The application then uses the credential management functions to obtain a handle to the credentials of the user on whose behalf they are executing. With this handle, the application can use the context management functions to create a security context to a service. A security context is an opaque data structure that contains the security data relevant to a connection, such as a session key, the duration of the session, and so on. Finally, the application uses the security context with the message support functions to ensure message integrity and privacy during the connection.

25.1    Security Package Capabilities

The capabilities of the security package determine what services it provides to the application. These capabilities include, for example, support for client-only authentication or mutual authentication, or support for message integrity and message privacy. In addition, some packages are designed for use only on reliable transport protocols and are not designed for use on datagram transports.

The security package capabilities available by a specific package are obtained using the QuerySecurityPackageInfo API. The following lists show the security package capabilities:

Applications will typically select security packages based on the type of security capabilities available to meet the application needs. More discussion on security package capabilities can be found in the section below on Security Context Semantics.

25.2    Initializing the Security Provider

This section describes how applications-level protocols initialize and use the Security Support Provider Interface. The section describes various stages of a secure network connection setup. The stages include:

These stages are described in the following sections.

25.2.1    Initializing the SSPI

Both the client and server use the same sequence of operations to initialize the security provider and select the appropriate security package.

Initializing the security interface involves the following steps:

The security function table contains the SSPI entry points for the security package. The function table is used to invoke the calls implemented by the security package.

25.3    Loading the Security Provider DLL

In order to initialize security, we need to ``load'' the provider. In all our discussions it will be assumed that the client side of the provider is a DLL..

The provider is loaded using a call to the LoadLibrary function, shown in the example below:

void * DllHandle;
//loading NTLM SSP
DllHandle = (void *)LoadLibrary(TEXT(``security.dll'');
if(!DllHandle)
{
 // 
 // DLL did not get loaded.
 //
 Status = GetLastError();
 return Status;
}
//
// DllHandle is valid
//

25.4    Provider Initialization

Once the provider has been loaded successfully, you need to perform some setup to use the security interface conveniently in the rest of the application. First, you need to get a pointer to the initialization function for the provider. Then you will use the initialization function to get a reference to the provider's security function table. Finally, you can get information from the provider about the security packages, or protocols, supported by this security provider. Each security package may have unique capabilities of interest to the application. However, in most cases, applications use security packages that support default or common capabilities.

The example below shows how to initialize the security provider.

//
// Initial provider setup.
//
INIT_SECURITY_INTERFACE  InitSecurityInterface;
PSecurityFunctionTable  SecurityInterface = 0;
SecPkgInfo  PAPI *    SecurityPackages;
DWORD    NumOfPkgs;
SECURITY_PROVIDER_INFO PAPI * List;
InitSecurityInterface = GetProcAddress(DllHandle, SECURITY_ENDPOINT);
if(!InitSecurityInterface)
{
 //
 // Something is amiss..
 //
}
//
// We got the InitSecurityInterface!
// Now use it to get the function table.
//
SecurityInterface = (*InitSecurityInterface)();
if(!SecurityInterface)
{
 //
 // we have a problem...
 //
}
//
// Lets find out the security packages supported by the provider.
//
Status = (*SecurityInterface->EnumerateSecurityPackages)( &NumOfPkgs, &SecurityPackages);
//
// Now using the capabilities information figure out which package you want to use.
//
PkgToUseIndex = -1;
for(I=0;I<NumOfPackages;I++)
{
 //
 // for example, if app needs integrity & privacy on messages, it checks
 //
 if(SecurityPackages[I].fCapabilities & (SECPKG_FLAG_INTEGRITY | SECPKG_FLAG_PRIVACY))
 {
  PkgToUseIndex = I;
  break;
 }
}
if(PkgToUseIndex > 0)
{
 //
 // Find out the maximum token size for this package
 //
 g_MaxToken = SecurityPackages[I].cbMaxToken;
}

Both the client and server need to agree on the security package they will use before the SSPI initialization steps shown above.

At this point the application has successfully initialized a security support provider and chosen a security package with sufficient capabilities needed by the application protocol. The SecurityInterface points to an array of function pointers as defined by SSPI.

Notice that the call to EnumerateSecurityPackages initializes the reference pointer SecurityPackages, with return data. Some SSPI functions have return output parameters, such as security package information. For the output data parameters, the caller passes in a pointer to a pointer to the return structure type, and the security provider allocates memory and returns the data to the caller by assigning the address of the return data buffer to the argument. The convention used by SSPI to return data is the following:

``The security package allocates, and the caller frees.''

Therefore, the calling program will use FreeContextBuffer to free the memory containing data allocated by the security provider when it is done referencing the data. The examples below will continue to reference SecurityPackages information, so it must be freed later.

25.5    Security Function Table

The Security Function Table is an array of function pointers which are defined in the include file, SSPI.H. The function names correspond to the interface specification for SSPI.

The definition of the Security Function Table is shown below:

typedef struct _SECURITY_FUNCTION_TABLE_W {
 unsigned long      dwVersion;
 ENUMERATE_SECURITY_PACKAGES_FN_W EnumerateSecurityPackagesW;
 void SEC_FAR *      Reserved1;
// QUERY_CREDENTIALS_ATTRIBUTES_FN_W QueryCredentialsAttributesW;
 ACQUIRE_CREDENTIALS_HANDLE_FN_W  AcquireCredentialsHandleW;
 FREE_CREDENTIALS_HANDLE_FN   FreeCredentialHandle;
 void SEC_FAR *      Reserved2;
 INITIALIZE_SECURITY_CONTEXT_FN_W InitializeSecurityContextW;
 ACCEPT_SECURITY_CONTEXT_FN   AcceptSecurityContext;
 COMPLETE_AUTH_TOKEN_FN    CompleteAuthToken;
 DELETE_SECURITY_CONTEXT_FN   DeleteSecurityContext;
 APPLY_CONTROL_TOKEN_FN    ApplyControlToken;
 QUERY_CONTEXT_ATTRIBUTES_FN_W  QueryContextAttributesW;
 IMPERSONATE_SECURITY_CONTEXT_FN  ImpersonateSecurityContext;
 REVERT_SECURITY_CONTEXT_FN   RevertSecurityContext;
 MAKE_SIGNATURE_FN     MakeSignature;
 VERIFY_SIGNATURE_FN     VerifySignature;
 FREE_CONTEXT_BUFFER_FN    FreeContextBuffer;
 QUERY_SECURITY_PACKAGE_INFO_FN_W QuerySecurityPackageInfoW;
 void SEC_FAR *      Reserved3;
 void SEC_FAR *      Reserved4;
 QUERY_SECURITY_CONTEXT_TOKEN_FN  QuerySecurityContextToken;
} SecurityFunctionTableW, SEC_FAR * PSecurityFunctionTableW;

25.5.1    Memory Use, Security Buffers, and Descriptor

Most of the SSPI functions have variable length arguments for the caller (application) to provide message data to the security package and for the security package to return security data to the caller. SSPI APIs use a parameter type, BufferDescriptor, to define the size and location of the variable length data. Security buffers are used by the caller, for example, to pass message data to the security package, or to receive an output security token.

Security buffers can be passed in as an array of buffers. The security buffer descriptor identifies the number of buffers and starting address of the buffer array. Each security buffer also has a buffer type field to identify the contents of the buffer.

The definition of security buffers, buffer descriptors, and buffer data types from SSPI.H are shown below:

//
// SecBuffer
//
// Generic memory descriptors for buffers passed in to the security
// API
//
typedef struct _SecBuffer {
 unsigned long cbBuffer;    // Size of the buffer, in bytes
 unsigned long BufferType;   // Type of the buffer (below)
 void SEC_FAR * pvBuffer;   // Pointer to the buffer
} SecBuffer, SEC_FAR * PSecBuffer;
typedef struct _SecBufferDesc {
 unsigned long ulVersion;   // Version number
 unsigned long cBuffers;    // Number of buffers
#ifdef MIDL_PASS
 [size_is(cBuffers)]
#endif
 PSecBuffer pBuffers;    // Pointer to array of buffers
} SecBufferDesc, SEC_FAR * PSecBufferDesc;
#define SECBUFFER_VERSION   0
#define SECBUFFER_EMPTY    0 // Undefined, replaced by provider
#define SECBUFFER_DATA    1 // Packet data
#define SECBUFFER_TOKEN    2 // Security token
#define SECBUFFER_PKG_PARAMS  3 // Package specific parameters
#define SECBUFFER_MISSING   4 // Missing Data indicator
#define SECBUFFER_EXTRA    5 // Extra data
#define SECBUFFER_STREAM_TRAILER 6 // Security Trailer
#define SECBUFFER_STREAM_HEADER  7 // Security Header
#define SECBUFFER_ATTRMASK   0xF0000000
#define SECBUFFER_READONLY   0x80000000 // Buffer is read-only

Each time a security API is called that takes a SecBufferDesc parameter, it should be setup with one or more SecBuffers. For example, there can be two security buffers, one that contains input message data and the other for the output opaque security token returned by the security package. The order of security buffers in the security buffer descriptor is not important but they should be tagged with appropriate type. Also, an input buffer that can not be modified by the security package should additionally be tagged as read only.

The size of the output buffer that is expected to contain the security token is important. An application can find the maximum token size for a security package during initial setup. The call to EnumerateSecurityPackages returns an array of pointers to security package information. The security package information structure contains maximum token size value. In the example code, the information is in SecPkgInfo.cbMaxToken. It can also be obtained later on using QuerySecurityPackageInfo.

The application initializes the buffer pointers and sizes in the buffer description to indicate where message data and other information may be found.

The example below shows how to initialize an array of security buffers. This particular case shows how input security buffers are initialized by the server-side of a connection in a call to AcceptSecurityContext. Note that the last buffer contains the opaque security token received by the client and the SECBUFFER_READONLY flag is also set.

SecBuffer  Buffers[3];
SecBufferDesc BufferDesc;
...
BufferDesc.ulVersion = SECBUFFER_VERSION;
BufferDesc.cBuffers = 3;
BufferDesc.pBuffers = &Buffers;
Buffers[0].cbBuffer = sizeof(Protocol_Header);
Buffers[0].BufferType = SECBUFFER_READONLY | SECBUFFER_DATA;
Buffers[0].pvBuffer = pHeader;
Buffers[1].cbBuffer = pHeader->MessageSize;
Buffers[1].BufferType = SECBUFFER_DATA;
Buffers[1].pvBuffer = pMessage;
Buffers[2].cbBuffer = pHeader->TrailerSize;
Buffers[2].BufferType = SECBUFFER_READONLY | SECBUFFER_TOKEN;
Buffers[2].pvBuffer = pSecurityTrailer;

25.6    Establishing an Authenticated Connection

In a client/server application protocol, a server typically binds to a well known communication port (for example, a socket, RPC interface, and so forth) and waits for clients to connect and request service. The role of security at connection setup is two fold:

Associated with these two basic requirements are other security issues, such as, the authentication information should not be prone to replay, corruption, and so on. The application does not need to worry about how these are handled. It can simply request it from the chosen provider which will encapsulate the underlying security protocol.

The protocol used to establish an authenticated connection involves the exchange of one or more ``security tokens'' between the security providers on each side. These tokens are sent as ``opaque'' messages by the two sides along with any other application protocol specific information. The application level protocol strips the security token out of the received message and passes on to the security package on their side to figure out if authentication is complete or if further exchange of tokens is required. Theoretically, the exchange of security tokens can continue ad infinitum, however, in practice it contains one to three legs of message exchange.

For example, NTLM authentication is based on the challenge/response scheme, and uses three legs to authenticate a client to the server, as shown in the figure below.

Figure 25-1:  NTLM Challenge Response Authentication Protocol via SSPI

25.6.1    Client Context Initialization

To establish a secure connection, the client needs to acquire an outbound credentials handle so that it can send over an authentication request to the server. The server creates a security context for the client from the authentication request. There are two client-side SSPI functions involved in authentication setup:

Using the reference to the Security Function Table initialized during the security provider setup stage, the client calls AcquireCredentialsHandle as follows:

//
// Acquire an out-bound Credentials handle using the chosen security package.
//
SecurityStatus = (*SecurityInterface->AcquireCredentialsHandle)(
     0,
     SecurityPackages[PkgToUseIndex].Name,
     SECPKG_CRED_OUTBOUND,
     0,
     0,
     0,
     0,
     &Credentials,
     &TimeStamp
     );

The arguments to AcquireCredentialHandle are the following:

Once the client has acquired an outbound credentials handle, it is ready to start the authentication protocol to establish a connection with the server. The application client calls the security package again to initialize the security context.

To initiate the first leg of the authentication, the client calls InitializeSecurityContext to obtain an initial security token that will be sent in a connection request message to the server.

The example of the client call to InitializeSecurityContext is shown below:

//
// Set up the Buffer Descriptor.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
//
// Lets get the authentication token from the security package
// to send to the server to request an authenticated connection.
//
SecurityStatus = (*SecurityInterface->InitializeSecurityContext(
    Credentials,
    0,
    ServerPrincipalName,
    ISC_REQ_USE_DCE_STYLE | ISC_REQ_DELEGATE |
    ISC_REQ_MUTUAL_AUTH |ISC_REQ_REPLAY_DETECT |
    ISC_REQ_SEQUENCE_DETECT |ISC_REQ_CONFIDENTIALITY |
    ISC_REQ_CONNECTION,
    0,
    0,
    0,
    0,
    &SecurityContext,
    BufferDescriptor,
    &ContextAttributes,
    &TimeStamp
    );

The arguments to InitializeSecurityContext are the following:

The client then uses the security token information received in the output buffer descriptor to generate a message to send to the server. The construction of the message in terms of placement of various buffers and so forth, is part of the application protocol and should be understood between the two parties.

The client checks the return status from InitializeSecurityContext to see if authentication will complete in a single call. Otherwise it expects to receive a server-side authentication token in a response message to continue the security protocol. The return status SEC_I_CONTINUE_NEEDED, indicates the security protocol requires multiple authentication messages.

25.6.2    Server Context Initialization

To establish an authenticated connection, the server needs to acquire a credentials handle so that it can receive an incoming authentication request from the client. The server's credentials may be used to authenticate the server in security protocols that support server authentication or mutual authentication. When a connection request is received, the server creates a local security context to represent the client. The server uses the security context to carry out future requests by the same client.

First, the server obtains a handle to its credentials, which may be defined by the service account used to start the server. It does so by calling AcquireCredentialsHandle as follows:

//
// Acquire an out-bound Credentials handle using the chosen security package.
//
SecurityStatus = (*SecurityInterface->AcquireCredentialsHandle)(
     0,
     SecurityPackages[PkgToUseIndex].Name,
     SECPKG_CRED_INBOUND,
     0,
     0,
     0,
     0,
     &Credentials,
     &TimeStamp
     );

The arguments to the server-side call to AcquireCredentialHandle are as follows:

The returned Credentials Handle should be assigned to a global variable that is used for the lifetime of the server process. The returned TimeStamp is a temporary variable.

The server can wait (in a listen state) until a connection request arrives before acquiring an inbound credentials handle or it may acquire the handle and then go into a listen state.

When the server receives a connection request message from a client, it creates a security context for the client using AcceptSecurityContext. The server initializes the SecurityBufferDescriptors to refer to sections of the data message received, rather than copying data to an alternate buffer.

The following example shows the call to AcceptSecurityContext.

//
// Set up the Input and OutputBuffer Descriptor using the information from message received
// from the client.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 1;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer.cbBuffer = InBufferLen;
InSecBuffer.BufferType = SECBUFFER_TOKEN;
InSecBuffer.pvBuffer = InBuffer;
//
// Lets initialize client's context from the SSP and see if 
// we need to send anything back to the client
//
SecurityStatus = (*SecurityInterface->AcceptSecurityContext(
    Credentials,
    0,
    InputBufferDescriptor,
    ISC_REQ_USE_DCE_STYLE | ISC_REQ_DELEGATE |
    ISC_REQ_MUTUAL_AUTH |ISC_REQ_REPLAY_DETECT |
    ISC_REQ_SEQUENCE_DETECT |ISC_REQ_CONFIDENTIALITY |
    ISC_REQ_CONNECTION,
    DataRepresentation,
    &SecurityContext,
    OutputBufferDescriptor,
    &ContextAttributes,
    &TimeStamp
    );

The arguments to AcceptSecurityContext are as follows:

The server checks the return status and output buffer descriptor to ensure there are no errors so far, otherwise it rejects the connection request. If there is information in the output buffer it bundles it into a response message to the client as per the application protocol.

If the return status requires the protocol to continue (SEC_I_CONTINUE_NEEDED or SEC_I_COMPLETE_AND_CONTINUE), then another message exchange with the client is required. Otherwise the authentication is complete. For third leg, the server waits for the client to respond with another message. Note that this wait maybe timed out so as to avoid a denial of service attack (a malicious client may never respond hanging this server thread, and soon it will hang all server threads!!).

25.6.3    Client Continuation

On receipt of the response from the server, the client decomposes the message and, using the continue status from the previous call, it calls InitializeSecurityContext again:

if(SecurityStatus == SEC_I_CONTINUE_NEEDED || SecurityStatus = SEC_I_COMPLETE_AND_CONTINUE)
{
//
// Set up the Input and OutputBuffer Descriptor using the information from message 
// received from the server.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 1;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer.cbBuffer = InBufferLen;
InSecBuffer.BufferType = SECBUFFER_TOKEN;
InSecBuffer.pvBuffer = InBuffer;
//
// 
SecurityStatus = (*SecurityInterface->InitializeSecurityContext(
    0,
    &SecurityContext,
    0,
    0,
    0,
    DataRepresentation,
    InputBufferDescriptor,
    0,
    &SecurityContext,
    OutputBufferDescriptor,
    &ContextAttributes,
    &TimeStamp
    );
}

The client checks the return status from this call and may be required to continue for another leg. It uses the information in the OutputBufferDescriptor to construct a message and sends it to the server.

25.6.4    Server Continuation

The server should be waiting for the response based on the return code from previous call to AcquireSecurityContext. To continue the authentication protocol, the server also calls AcceptSecurityContext again.

if(SecurityStatus = SEC_I_CONTINUE_NEEDED || SecurityStatus = SEC_I_COMPLETE_AND_CONTINUE)
{
//
// Set up the Input and OutputBuffer Descriptor using the information from message
// receivedfrom the client.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 1;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer.cbBuffer = BufferLen;
OutSecBuffer.BufferType = SECBUFFER_TOKEN;
OutSecBuffer.pvBuffer = Buffer;
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 1;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer.cbBuffer = InBufferLen;
InSecBuffer.BufferType = SECBUFFER_TOKEN;
InSecBuffer.pvBuffer = InBuffer;
//
// Lets do the next leg of client's context initialization from the security package and see if we need
// to send anything back to the client
//
SecurityStatus = (*SecurityInterface->AcceptSecurityContext(
    0,
    &SecurityContext,
    InputBufferDescriptor,
    0,
    DataRepresentation,
    &SecurityContext,
    OutputBufferDescriptor,
    &ContextAttributes,
    &TimeStamp
    );
}

The return status is checked to see if the server needs to wait for another leg from the client. In most existing authentication protocols this is the maximum even for mutual authentication. NTLM security package performs client authentication and Kerberos security package does mutual authentication in three legs.

25.7    Secure Message Exchange

The Microsoft SSPI provides message APIs that can be used to ensure application protocol message integrity. Message privacy APIs (data encryption) are not exposed directly but a particular provider may expose them and document them separately.

If the application wants to generate signed messages, the client must have specified the ISC_REQ_REPLAY_DETECT or ISC_REQ_SEQUENCE_DETECT flag as the Context Attributes argument in the first call to the InitializeSecurityContext function.

After an authenticated connection has been established, the security support providers on each side establish a common session key that is used to sign messages on the sending side and to verify messages on the receiving side. The algorithms used in message signatures are private to the security package.

The SSPI message APIs are the following:

25.7.1    Sender

The sender of a message calls MakeSignature API to get a signature for the message and appends it to the message at an appropriate place so that the receiver is able to extract it on receipt:

//
// Setup the Buffer Descriptors.
//
OutBufferDesc.ulVersion = 0;
OutBufferDesc.cBuffers = 2;
OutBufferDesc.pBuffers = &OutSecBuffer;
OutSecBuffer[0].cbBuffer = MessageLen;
OutSecBuffer[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
OutSecBuffer[0].pvBuffer = Message;
OutSecBuffer[1].cbBuffer = SignatureLen;
OutSecBuffer[1].BufferType = SECBUFFER_EMPTY;
OutSecBuffer[1].pvBuffer = (Message + MessageLen); // just after the message
//
// Now call MakeSignature API to get it signed.
//
SecurityStatus = (*SecurityInterface->MakeSignature)(
     &SecurityContext,
0,
BufferDescriptor,
Sequence
);

The arguments to MakeSignature are the following:

The sender then uses the buffer descriptor (including the signature) to construct a message to send to the receiver.

The quality of protection value allows applications to select different cryptographic algorithms supported by the security package. By default NTLM does not support this parameter. Other security packages, however, may provide different quality of protection options.

25.7.2    Receiver

The receiver takes the message and breaks it down to create the buffer descriptor as before. It then passes this buffer descriptor on to the VerifySignature API to verify the message integrity.

//
// Setup the Buffer Descriptors.
//
InBufferDesc.ulVersion = 0;
InBufferDesc.cBuffers = 2;
InBufferDesc.pBuffers = &InSecBuffer;
InSecBuffer[0].cbBuffer = MessageLen;
InSecBuffer[0].BufferType = SECBUFFER_DATA | SECBUFFER_READONLY;
InSecBuffer[0].pvBuffer = Message;
InSecBuffer[1].cbBuffer = SignatureLen;
InSecBuffer[1].BufferType = SECBUFFER_TOKEN;
InSecBuffer[1].pvBuffer = (Message + MessageLen); // just after the message
//
// Now call MakeSignature API to get it signed.
//
SecurityStatus = (*SecurityInterface->VerifySignature)(
     &SecurityContext,
BufferDescriptor,
Sequence,
&QualityOfProtection
);

The arguments to VerifySignature are the following:

Once the receiver is ensured of the authenticity and integrity of the message, the receiver is free to use it as per the application protocol.

25.7.3    Impersonation

An important aspect of client/server communication besides authentication and message exchange is the ability of a server to determine whether it should service the client's request. A large number of servers run under system's context and therefore have far more privileges and abilities than a typical client requesting service. An example of this is a network file server which has full access to all files, whereas requesting users may not. Therefore, the server should carry out a client request if and only if the client has sufficient access rights for the requested service.

There are two approaches for determining whether a client has sufficient access rights for the operation: an access check by the server, or an access check by the system. The brute force approach builds the logic of doing authorization checks for client access into the server. The server code uses authorization information, for example, from a separate authorization file, and determines if the client has sufficient rights to perform the requested operation.

SSPI provides an API, ImpersonateSecurityContext, that allows a server to impersonate the client's security context as well as to revert back to its own security context (RevertSecurityContext) when done servicing.

The example below shows how to use ImpersonateSecurityContext and RevertSecurityContext APIs:

//
// When accessing a resource on behalf the client, we need to 
// impersonate the client so that appropriate access check is done.
//
SecurityStatus = (*SecurityInterface->ImpersonateSecurityContext) (&SecurityContext);
if(SecurityStatus != SEC_E_OK)
{
 //
 // We have a problem...
 // This security context is not at least impersonation level.
 //
 return error;
}
//
// At this point the calling thread is under an impersonation token with client's credentials
//
//
// Process the request..
//
. . .
//
// Revert to primary token once we are done.
//
SecurityStatus = (*SecurityInterface->RevertSecurityContext)(&SecurityContext);
if(SecurityStatus != SEC_E_OK)
{
 //
 // check for any errors...
 //
 return error;
}
//
// The server thread is back to its original context.
//

25.7.4    Using Delegation in Kerberos

The Kerberos authentication protocol supports delegation. When delegation is supported, the impersonating server can use the client's delegation level credentials to initialize a security context with a remote server to request a service on the client's behalf.

Consider how a client's security context, identified by C, is established on a server called Server 1. When Server 1 impersonates the client, the impersonation context on Server 1 is identified as C/S1. Server 1 makes an off-machine connection to Server 2. Through the use of delegation, Server 2 is also able to impersonate the client's security context. Server 2's impersonation of the client is identified as C/S2.

The following example shows how delegation can be accomplished using SSPI:

//
// When accessing a resource on behalf the client, we need to impersonate the client so that
// appropriate access check is done.
//
SecurityStatus = (*SecurityInterface->ImpersonateSecurityContext)(&SecurityContext);
if(SecurityStatus != SEC_E_OK)
{
 //
 // We have a problem...
 // This security context is not at least impersonation level.
 //
 return error;
}
//
// At this point the calling thread is under an impersonation token with client's credentials
//
//
// Now we can call InitializeSecurityContext to get an authentication token with ``current''
// credentials (client's) to send to another remote server:
//
// Set up security buffers and the descriptor.
//
//
// Call InitializeSecurityContext...
// If this fails, then the client security context is not delegation level,
// WATCH OUT FOR THIS, and handle according to the application protocol.
//
//
// construct a message with the auth token from the SSP to send to the remote server.
// and send the message.
//
// Wait for the reply from the server.
//
//
// If SEC_I_CONTINUE_NEEDED is returned by the first call to Initialize, use
// the auth token returned by the remote server to call InitializeSecurityContext again.
//
if(SecurityStatus == SEC_I_CONTINUE_NEEDED || SecurityStatus = SEC_I_COMPLETE_AND_CONTINUE)
{
 //
 // Fill up Input security buffers and setup output security buffers.
 //
 //
 // call InitializeSecurityContext.
 //
 //
 // Convert the security buffers into a message.
 // and send the message.
 //
 //
 // wait for reply.
 //
}
//
// At this point the connection is established.
//
// 
// Request service from the remote server by exchanging messages. Note that
// the remote server will process these assuming that they are coming from the client.
//
. . .
//
// Once done, tear down the connection.
//
//
// Now, you may revert to primary token.
//
SecurityStatus = (*SecurityInterface->RevertSecurityContext)(&SecurityContext);
if(SecurityStatus != SEC_E_OK)
{
 //
 // check for any errors...
 //
 return error;
}
//
// The server thread is back to its original context.
//

25.7.5    Security Context Details

The Security Support Provider Interface model supports three types of security contexts, which are summarized in the following table.

Table 25-1:  Security Contexts

Type Description
Connection A connection-oriented context is the most common security context, and the simplest to use. The caller is responsible for the overall message format. The caller is responsible for the location of the data in the message. The caller is also responsible for the location of the security-relevant fields within a message, such as the location of the signature data.
Datagram A datagram-oriented context has extra support for DCE RPC style datagram communication. It can also be used generically for a datagram-oriented transport application.
Stream A stream-oriented context is responsible for the blocking and message formatting within the security package. The caller is not interested in formatting, but rather a raw stream of data.

25.7.5.1    Connection-Oriented Contexts

With a connection-oriented context, the caller of the function is responsible for formatting messages. The caller also relies on the security provider to authenticate connections, and to ensure the integrity of specific parts of the message. Most of the range of context options are available to connection-oriented contexts. These options include mutual authentication, replay detection, and sequence detection, as described in Context Requirements.

A security package sets the SECPKG_FLAG_CONNECTION flag to indicate that it supports connection-oriented semantics.

25.7.5.2    Datagram Contexts

Datagram, or connectionless, contexts have slightly different semantics from connection-oriented contexts. A connectionless context implies that the server has no way of determining when the client has shut down or otherwise terminated the connection. In other words, no termination notice is passed from the transport application to the server, as would occur in a connection context. To better support some models, particularly DCE-style RPC, the following rules apply when the client specifies the ISC_REQ_DATAGRAM flag in its call to the InitializeSecurityContext function:

A security package sets the SECPKG_FLAG_DATAGRAM flag to indicate that it supports datagram semantics.

25.7.5.3    Stream Contexts

Stream contexts are quite different from either connection or datagram contexts. Stream contexts were introduced to handle the secure streams-oriented protocols such as SSL or PCT.

In the interest of sharing the same interface, similar credential management, and so on, the Security Support Provider Interface has been extended to provide support for stream contexts. The security protocol incorporated both the authentication scheme, and the record formats. This posed a problem to the typical implementation, which required the blocking to be done by the caller.

To satisfy the requirements of the stream-oriented protocols, a security package that supports stream contexts has the following characteristics:

Obviously, the final item is of the most interest. By specifying stream semantics, the caller is indicating a willingness to do extra work so the security provider can handle the blocking of the messages.

In essence, for the MakeSignature and VerifySignature functions, the caller passes in a list of buffers. When a message is received from a channel that is stream-oriented (such as a TCP port), the caller passes in a buffer list as follows:

Table 25-2:  Buffer Lists

Buffer Length Buffer Type
1 MessageLength SECBUFFER_DATA
2 0 SECBUFFER_EMPTY
3 0 SECBUFFER_EMPTY
4 0 SECBUFFER_EMPTY
5 0 SECBUFFER_EMPTY

The security package then goes to work on the blob. If the function returns successfully, the buffer list looks like this:

Table 25-3:  Buffer List after Successful Return

Buffer Length Buffer Type
1 Header Length SECBUFFER_STREAM_HEADER
2 Data Length SECBUFFER_DATA
3 Trailer Length SECBUFFER_STREAM_TRAILER
4 0 SECBUFFER_EMPTY
5 0 SECBUFFER_EMPTY

The provider could have also returned buffer #4 as follows:

Buffer Length Buffer Type
4 x SECBUFFER_EXTRA

This indicates that the data in this buffer is part of the next record, and has not yet been processed.

Conversely, if the message function returns the SEC_E_INCOMPLETE_MESSAGE error code, the returned buffer list would look like this:

Buffer Length Buffer Type
1 x SECBUFFER_MISSING

This indicates that more data was needed to process the record. Unlike most errors returned from a message function, this buffer type does not indicate that the context has been compromised, just that more data is needed. Security providers must not update their state in this condition.

Similarly, on the send side of the communication, the caller can simply call the MakeSignature function, in which case the security package may need to reallocate the buffer, copy things around, and so on. Or the caller can be more efficient by providing a buffer list as follows:

Buffer Length Type
1 Header Length SECBUFFER_STREAM_HEADER
2 Data Length SECBUFFER_DATA
3 Trailer Length SECBUFFER_STREAM_TRAILER

This allows the caller to use the buffers more efficiently. By calling the QueryContextAttributes function to determine the amount of space to reserve before calling MakeSignature, the operation is more efficient for the application and the security package.

25.7.5.4    Context Requirements

Context requirements are expressed as a combination of bit flags, passed to either the InitializeSecurityContext or AcceptSecurityContext function. These flags affect the context in a number of ways, and are detailed in the following table. Not all flags apply to all contexts; some are valid only for the server, others only for the client.

The caller uses the fContextReq parameter of the InitializeSecurityContext or AcceptSecurityContext call to specify a set of flags that indicate the required capabilities. When the function returns, the pfContextAttr parameter indicates the attributes of the established context. The caller is responsible for determining whether the final context attributes are acceptable. For example, if the caller requested mutual authentication, but the security package indicates that it was not or could not be performed, the caller must decide whether to cancel the context or continue on.

The following table describes the various context requirements.

Table 25-4:  Context Requirements

Type Description
DELEGATE Indicates that the server in the transport application should be allowed simple delegation rights, that is, impersonation of the client on the node at which the server is executing.
MUTUAL_AUTH Indicates that both parties must authenticate the identity of the peer.
REPLAY_DETECT Indicates that the context should be established to allow detection of replayed packets later through the message support functions, MakeSignature and VerifySignature. Implies INTEGRITY.
SEQUENCE_DETECT Indicates that the context should be established to allow detection of out-of-order delivery of packets later through the message support functions. Implies INTEGRITY.
CONFIDENTIALITY Indicates that the context should be established to protect data while in transit. Reserved for future use.
USE_SESSION_KEY Indicates that a new session key should be negotiated.
PROMPT_FOR_CREDS Indicates that, if the client is an interactive user, the security package should prompt the user for the appropriate credentials to use, if possible.
USE_SUPPLIED_CREDS Indicates that package-specific credential information is available in the input buffer. The security package should use these credentials to authenticate the connection.
ALLOCATE_MEMORY Indicates that the security package should allocate the memory. The caller must eventually call the FreeContextBuffer function to free memory allocated by the security package.
USE_DCE_STYLE Indicates that the caller expects a three-leg authentication transaction.
DATAGRAM Indicates that datagram semantics should be used. For more information, see Section 25.7.5.2.
CONNECTION Indicates that connection semantics should be used. For more information, see Section 25.7.5.1.
STREAM Indicates that stream semantics should be used. For more information, see Section 25.7.5.3.
EXTENDED_ERROR Indicates that if the context fails (or failed), it will generate an error reply message for the peer.
INTEGRITY Buffer integrity can be verified, but no sequencing or reply detection is enabled.

25.8    Datatype Descriptions

25.8.1    BINDPTR

A union containing a pointer to a FUNCDESC, VARDESC, or an ITypeComp() interface. It is defined as follows:

typedef union tagBINDPTR {
    FUNCDESC FAR* lpfuncdesc;
    VARDESC FAR* lpvardesc;
    ITypeComp FAR* lptcomp;
} BINDPTR;

25.8.2    BOOL

Boolean variable (should be TRUE or FALSE).

Header file: WTYPES.H

typedef long BOOL;

25.8.3    BSTR

A length-prefixed string used by Automation data manipulation functions.

typedef OLECHAR *BSTR;

BSTRs are wide, double-byte (Unicode) strings on 32-bit Windows platforms and narrow, single-byte strings on the Apple® PowerMac(TM).

Header file: WTYPES.H

typedef [wire_marshal( wireBSTR )] OLECHAR *  BSTR;

25.8.4    BYTE

BYTE is an unsigned character data type that is binary data.

Header file: WINDEF.H

typedef unsigned char     BYTE;

25.8.5    CLIPFORMAT

typedef
union _userCLIPFORMAT switch(long fContext) u
{
    case WDT_INPROC_CALL:	     DWORD     dwValue;
    case WDT_REMOTE_CALL:   [string] wchar_t * pwszName;
} userCLIPFORMAT;
typedef [unique] userCLIPFORMAT *  wireCLIPFORMAT;
typedef [wire_marshal(wireCLIPFORMAT)] WORD  CLIPFORMAT;

25.8.6    CONST

Variable that remains constant during an execution.

Header file: WTYPES.H

#define CONST const

25.8.7    CUSTDATA

Used for retrieving custom data. It is defined as follows:

typedef struct  tagCUSTDATA
    {
    DWORD cCustData;
    /* [size_is] */ LPCUSTDATAITEM prgCustData;
    }    CUSTDATA;

The following table describes the fields of the CUSTDATA structure.

Value Description
cCustData Number of custom data items in prgCustData
prgCustData Array of custom data items

25.8.8    DISPID

Used by IDispatch::Invoke() to identify methods, properties, and arguments.

typedef LONG DISPID;

The following dispatch identifiers (DISPIDs) have special meaning.

DISPID Description
DISPID_VALUE The default member for the object. This property or method is invoked when an ActiveX client specifies the object name without a property or method.
DISPID_NEWENUM The _NewEnum property. This special, restricted property is required for collection objects. It returns an enumerator object that supports IEnumVARIANT, and should have the restricted attribute specified in Object Definition Language.
DISPID_EVALUATE The Evaluate method. This method is implicitly invoked when the ActiveX client encloses the arguments in square brackets. For example, the following two lines are equivalent: x.[A1:C1].value = 10x.Evaluate("A1:C1").value = 10 The Evaluate method has the DISPID DISPID_EVALUATE.
DISPID_PROPERTYPUT The parameter that receives the value of an assignment in a PROPERTYPUT.
DISPID_CONSTRUCTOR The C++ constructor function for the object.
DISPID_DESTRUCTOR The C++ destructor function for the object.
DISPID_UNKNOWN The value returned by IDispatch::GetIDsOfNames() to indicate that a member or parameter name was not found.

Note: The reserved DISPIDs are:

25.8.9    DISPPARAMS

Used by IDispatch::Invoke() to contain the arguments passed to a method or property.

typedef struct FARSTRUCT tagDISPPARAMS{
VARIANTARG FAR* rgvarg;               // Array of arguments.
    DISPID FAR* rgdispidNamedArgs;    // Dispatch IDs of named arguments.
    unsigned int cArgs;               // Number of arguments.
    unsigned int cNamedArgs;          // Number of named arguments.
} DISPPARAMS;

25.8.10    DWORD

A 32-bit unsigned integer or the address of a segment and its associated offset.

Header file: WTYPES.H

typedef unsigned long DWORD;

25.8.11    FAR *

Defined to nothing.

#define far
#define FAR far

25.8.12    FUNCDESC

Describes a function, and is defined as follows:

typedef struct tagFUNCDESC {
    MEMBERID memid;         // Function member ID.
/* [size_is] */ SCODE __RPC_FAR *lprgscode;
/* [size_is] */ ELEMDESC __RPC_FAR *lprgelemdescParam;
    FUNCKIND funckind;      // Specifies whether the
                            // function is virtual, static,
                            // or dispatch-only.
    INVOKEKIND invkind;     // Invocation kind. Indicates if this is a
                            // property function, and if so, what kind.
    CALLCONV callconv;      // Specifies the function's calling 
                            // convention.
    short cParams;          // Count of total number of parameters.
    short cParamsOpt;       // Count of optional parameters (detailed
                            // description follows).
    short oVft;             // For FUNC_VIRTUAL, specifies the offset in
                            // the VTBL.
    short cScodes;          // Count of permitted return values. 
    ELEMDESC elemdescFunc;  // Contains the return type of the function.
    WORD wFuncFlags;        // Definition of flags follows.
}    FUNCDESC;

The cParams field specifies the total number of required and optional parameters. The cParamsOpt field specifies the form of optional parameters accepted by the function, as follows:

25.8.13    HANDLE

A pointer to any type.

Header file: WTYPES.H

typedef void *HANDLE;

25.8.14    HBITMAP

Handle to a bitmap.

typedef HANDLE HBITMAP;

25.8.15    HENHMETAFILE

Handle to an enhanced metafile.

typedef HANDLE HENHMETAFILE;

25.8.16    HGLOBAL

Handle to a global memory block.

typedef HANDLE HGLOBAL;

25.8.17    HINSTANCE

Handle to an instance.

typedef HANDLE HINSTANCE;

25.8.18    HKEY

Handle to a registry key.

typedef HANDLE HKEY;

25.8.19    HMETAFILEPICT

typedef
struct _remoteMETAFILEPICT
{
    long            mm;
    long            xExt;
    long            yExt;
    userHMETAFILE * hMF;
} remoteMETAFILEPICT;
typedef union _userHMETAFILEPICT switch( long fContext ) u
{
    case WDT_INPROC_CALL:   long                hInproc;
    case WDT_REMOTE_CALL:   remoteMETAFILEPICT* hRemote;
    default:                long                hGlobal;
} userHMETAFILEPICT;

25.8.20    HREFTYPE

A handle that identifies a type description.

typedef unsigned long HREFTYPE;

25.8.21    HTASK

A handle to a task.

typedef HANDLE HTASK;

25.8.22    HUGEP

#ifndef HUGEP
#if defined(_WIN32) || defined(_MPPC_)
#define HUGEP
#else
#define HUGEP __huge
#endif // WIN32
#endif // HUGEP

25.8.23    INVOKEKIND

Defined as follows:

typedef enum tagINVOKEKIND {
    INVOKE_FUNC = DISPATCH_METHOD,
    INVOKE_PROPERTYGET = DISPATCH_PROPERTYGET,
    INVOKE_PROPERTYPUT = DISPATCH_PROPERTYPUT,
    INVOKE_PROPERTYPUTREF = DISPATCH_PROPERTYPUTREF
} INVOKEKIND;

Value Description
INVOKE_FUNC The member is called using normal function invocation syntax.
INVOKE_PROPERTYGET The function is invoked using normal property-access syntax.
INVOKE_PROPERTYPUT The function is invoked using property value assignment syntax. Syntactically, a typical programming language might represent changing a property in the same way as assignment. For example:object.property : = value.
INVOKE_PROPERTYPUTREF The function is invoked using property reference assignment syntax.

In C, value assignment is written as *pobj1 = *pobj2, while reference assignment is written as pobj1 = pobj2. Other languages have other syntactic conventions. A property or data member can support only a value assignment, a reference assignment, or both. The INVOKEKIND enumeration constants are the same constants that are passed to IDispatch::Invoke() to specify the way in which a function is invoked.

25.8.24    IPID

Interface pointer identifier. It is identical to a GUID.

typedef GUID IPID;

25.8.25    LANGID

Language identifier.

The first release of Windows NT supports 35 sublanguages/locales. The following 28 sublanguages/locales use the Latin 1 script:

Table 25-5:  Sublanguages Using the Latin 1 Script

Identifier Language Sublanguage/Locale Language Code
0x0406 Danish Danish DAN
0x0413 Dutch Dutch (Standard) NLD
0x0813 Dutch Belgian (Flemish) NLB
0x0409 English American ENU
0x0809 English British ENG
0x0c09 English Australian ENA
0x1009 English Canadian ENC
0x1409 English New Zealand ENZ
0x1809 English Ireland ENI
0x040b Finnish Finnish FIN
0x040c French French (Standard) FRA
0x080c French Belgian FRB
0x0c0c French Canadian FRC
0x100c French Swiss FRS
0x0407 German German (Standard) DEU
0x0807 German Swiss DES
0x0c07 German Austrian DEA
0x040f Icelandic Icelandic ISL
0x0410 Italian Italian (Standard) ITA
0x0810 Italian Swiss ITS
0x0414 Norwegian Norwegian (Bokmal) NOR
0x0814 Norwegian Norwegian (Nynorsk) NON
0x0416 Portuguese Portuguese (Brazilian) PTB
0x0816 Portuguese Portuguese (Standard) PTG
0x041D Swedish Swedish SVE
0x040a Spanish Spanish (Standard/Traditional) ESP
0x080a Spanish Mexican ESM
0x0c0a Spanish Spanish (Modern) ESN

The following 5 sublanguages/locales use the Latin 2 script:

Table 25-6:  Sublanguages Using Latin 2 Script

Identifier Sublanguage/Locale Language Code
0x041f Turkish TRK
0x0415 Polish PLK
0x0405 Czech CSY
0x041b Slovak SKY
0x040e Hungarian HUN

The following sublanguage/locale uses the Cyrillic script:

Table 25-7:  Sublanguages and Locales Using Cyrillic Script

Identifier Sublanguage/Locale Language Code
0x0419 Russian RUS

The following sublanguage/locale uses the Other script:

Table 25-8:  Sublanguages and Locales Using Other Script

Identifier Sublanguage/Locale Language Code
0x0408 Greek ELL

The following special identifiers are also defined:

Table 25-9:  Special Identifiers

Identifier Sublanguage/Locale
0x0000 Language-Neutral
0x0400 Process Default Language

25.8.26    LCID

Identifies a locale for national language support. Locale information is used for international string comparisons and localized member names.

typedef unsigned long LCID;

25.8.27    LCTYPE

An LCTYPE constant is a constant that specifies a particular piece of locale information. The values in the following list correspond to the names of these values in the configuration registry, under both the user's preferences (as values in the registry key HKEY_CURRENT_USER\Control Panel\International) and the system's installed languages (as files pointed to by registry keys, one key per language installed, under HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\NLS). All values are null-terminated Unicode(TM) strings. If no maximum length is indicated, the strings may vary in length.

Table 25-10:  LCTYPE Values

Constant Description
LOCALE_ILANGUAGE Language identifier indicating the language. The maximum number of characters allowed for this string is 5.
LOCALE_SLANGUAGE Full localized name of the language.
LOCALE_SENGLANGUAGE Full English name of the language from the International Organization for Standardization (ISO) Standard 639. This is always restricted to characters mappable into the ASCII 127-character subset.
LOCALE_SABBREVLANGNAME Abbreviated name of the language, created by taking the 2-letter language abbreviation from the ISO Standard 639 and adding a third letter, as appropriate, to indicate the sublanguage.
LOCALE_SNATIVELANGNAME Native name of the language.
LOCALE_SSORTNAME The full localized name of the sort for the given locale ID.
LOCALE_ICOUNTRY Country code, based on international phone codes, also referred to as IBM country codes. The maximum number of characters allowed for this string is 6.
LOCALE_SCOUNTRY Full localized name of the country.
LOCALE_SENGCOUNTRY Full English name of the country. This is always restricted to characters mappable into the ASCII 127-character subset.
LOCALE_SABBREVCTRYNAME Abbreviated name of the country from the ISO Standard 3166.
LOCALE_SNATIVECTRYNAME Native name of the country.
LOCALE_IDEFAULTLANGUAGE Language identifier for the principal language spoken in this locale. This is provided so that partially specified locales can be completed with default values. The maximum number of characters allowed for this string is 5.
LOCALE_IDEFAULTCOUNTRY Country code for the principal country in this locale. This is provided so that partially specified locales can be completed with default values. The maximum number of characters allowed for this string is 6.
LOCALE_IDEFAULTANSICODEPAGE American National Standards Institute (ANSI) code page associated with this locale. The maximum number of characters allowed for this string is 6.
LOCALE_IDEFAULTOEMCODEPAGE Original equipment manufacturer (OEM) code page associated with the locale. The maximum number of characters allowed for this string is 6.
LOCALE_IDEFAULTCODEPAGE Original equipment manufacturer (OEM) code page associated with the country. The maximum number of characters allowed for this string is 6.
LOCALE_IDEFAULTEBCDICCODEPAGE Default EBCDIC code page associated with the locale. The maximum number of characters allowed for this string is 6.
LOCALE_SLIST Character(s) used to separate list items. For example, a comma is used in many locales.
LOCALE_IMEASURE System of measurement. This value is 0 if the metric system (Systéme International d'Unités, or S.I.) is used and 1 if the U.S. system is used. The maximum number of characters allowed for this string is 2.
LOCALE_SDECIMAL Character(s) used as the decimal separator.
LOCALE_STHOUSAND Character(s) used to separate groups of digits to the left of the decimal.
LOCALE_SGROUPING Sizes for each group of digits to the left of the decimal. An explicit size is needed for each group; semicolons separate sizes. If the last value is zero, the proceeding value is repeated. To group thousands, specify 3;0, for example.
LOCALE_IDIGITS Number of fractional digits. The maximum number of characters allowed for this string is 3.
LOCALE_ILZERO Specifier for leading zeros in decimal fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-11:  LOCALE_ILZERO Values

Value Meaning
0 No leading zeros
1 Leading zeros

Table 25-12:  LCTYPE Values (continued)

LOCALE_INEGNUMBER Negative number mode. The mode can be one of these values:

Table 25-13:  LOCALE_INEGNUMBER Values

Value Meaning
0 (1.1)
1 -1.1
2 - 1.1
3 1.1-
4 1.1 -

Table 25-14:  LCTYPE Values (continued)

LOCALE_SNATIVEDIGITS Native equivalents to ASCII 0 through 9.
LOCALE_SENGCURRNAME The full English name of the currency associated with the locale.
LOCALE_SNATIVECURRNAME The native name of the currency associated with the locale.
LOCALE_SCURRENCY String used as the local monetary symbol.
LOCALE_SINTLSYMBOL Three characters of the international monetary symbol specified in ISO 4217, "Codes for the Representation of Currencies and Funds," followed by the character separating this string from the amount.
LOCALE_SMONDECIMALSEP Character(s) used as the monetary decimal separator.
LOCALE_SMONTHOUSANDSEP Character(s) used as the monetary separator between groups of digits to the left of the decimal.
LOCALE_SMONGROUPING Sizes for each group of monetary digits to the left of the decimal. An explicit size is needed for each group; sizes are separated by semicolons. If the last value is zero, the preceding value is repeated. To group thousands, specify 3;0, for example.
LOCALE_ICURRDIGITS Number of fractional digits for the local monetary format. The maximum number of characters allowed for this string is 3.
LOCALE_IINTLCURRDIGITS Number of fractional digits for the international monetary format. The maximum number of characters allowed for this string is 3.
LOCALE_ICURRENCY Positive currency mode. The maximum number of characters allowed for this string is 2. The mode can be one of the following values:

Table 25-15:  LOCALE_ICURRENCY Values

Value Meaning
0 Prefix, no separation
1 Suffix, no separation
2 Prefix, 1-char. separation
3 Suffix, 1-char. separation

Table 25-16:  LCTYPE Values (continued)

LOCALE_INEGCURR Negative currency mode. The maximum number of characters allowed for this string is 3. The mode can be one of the following values:

Table 25-17:  LOCALE_INEGCURR Values

Value Example
0 ($1.1)
1 -$1.1
2 $-1.1
3 $1.1-
4 (1.1$)
5 -1.1$
6 1.1-$
7 1.1$-
8 -1.1 $ (space before $)
9 -$ 1.1 (space after $)
10 1.1 $- (space before $)
11 $ 1.1- (space after $)
12 $ -1.1 (space after $)
13 1.1- $ (space before $)
14 ($ 1.1) (space after $)
15 (1.1 $) (space before $)

Table 25-18:  LCTYPE Values (continued)

LOCALE_SDATE Character(s) for the date separator.
LOCALE_STIME Character(s) for the time separator.
LOCALE_STIMEFORMAT Time formatting strings for this locale. The string can consist of a combination of the hour, minute, and second format pictures defined in the National Language Support Constants table.
LOCALE_SYEARMONTH The Year/Month formatting string for the locale. This string shows the proper format for a date string that contains only the year and the month.
LOCALE_SSHORTDATE Short date formatting string for this locale. The string can consist of a combination of day, month, and year format pictures defined in the National Language Support Constants table.
LOCALE_SLONGDATE Long date formatting string for this locale. The string can consist of a combination of day, month, and year format pictures defined in the National Language Support Constants table and any string of characters enclosed in single quotes. Characters in single quotes remain as given.
LOCALE_IDATE Short date format-ordering specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-19:  LOCALE_IDATE Values

Value Meaning
0 Month-Day-Year
1 Day-Month-Year
2 Year-Month-Day

Table 25-20:  LCTYPE Values (continued)

LOCALE_ILDATE Long date format-ordering specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-21:  LOCALE_ILDATE Values

Value Meaning
0 Month-Day-Year
1 Day-Month-Year
2 Year-Month-Day

Table 25-22:  LCTYPE Values (continued)

LOCALE_ITIME Time format specifier. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-23:  LOCALE_ITIME Values

Value Meaning
0 AM / PM 12-hour format
1 24-hour format

Table 25-24:  LCTYPE Values (continued)

LOCALE_ICENTURY Specifier for full 4-digit century. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-25:  LOCALE_ICENTURY Values

Value Meaning
0 Abbreviated 2-digit century
1 Full 4-digit century

Table 25-26:  LCTYPE Values (continued)

LOCALE_ITLZERO Specifier for leading zeros in time fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-27:  LOCALE_ITLZERO Values

Value Meaning
0 No leading zeros for hours
1 Leading zeros for hours

Table 25-28:  LCTYPE Values (continued)

LOCALE_IDAYLZERO Specifier for leading zeros in day fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-29:  LOCALE_IDAYLZERO Values

Value Meaning
0 No leading zeros for days
1 Leading zeros for days

Table 25-30:  LCTYPE Values (continued)

LOCALE_IMONLZERO Specifier for leading zeros in month fields. The maximum number of characters allowed for this string is 2. The specifier can be one of the following values:

Table 25-31:  LOCALE_IMONLZERO Values

Value Meaning
0 No leading zeros for months
1 Leading zeros for months

Table 25-32:  LCTYPE Values (continued)

LOCALE_S1159 String for the AM designator.
LOCALE_S2359 String for the PM designator.
LOCALE_ICALENDARTYPE Current calendar type. This type can be one of these values:

Table 25-33:  LOCALE_S1159 Values

Value Meaning
1 Gregorian (as in United States)
2 Gregorian (English strings always)
3 Era: Year of the Emperor (Japan)
4 Era: Year of Taiwan Region
5 Tangun Era (Korea)

Table 25-34:  LCTYPE Values (continued)

LOCALE_IOPTIONALCALENDAR Additional calendar types. This can be a zero-separated list of one or more of these calendars type values:

Table 25-35:  LOCALE_IOPTIONALCALENDAR Values

Value Meaning
0 No additional types valid
1 Gregorian (as in United States)
2 Gregorian (English strings always)
3 Era: Year of the Emperor (Japan)
4 Era: Year of Taiwan Region
5 Tangun Era (Korea)

Table 25-36:  LCTYPE Values (continued)

LOCALE_IFIRSTDAYOFWEEK Specifier for the first day in a week. The specifier can be one of these values:

Table 25-37:  LOCALE_IFIRSTDAYOFWEEK Values

Value Meaning
0 LOCALE_SDAYNAME1
1 LOCALE_SDAYNAME2
2 LOCALE_SDAYNAME3
3 LOCALE_SDAYNAME4
4 LOCALE_SDAYNAME5
5 LOCALE_SDAYNAME6
6 LOCALE_SDAYNAME7

Table 25-38:  LCTYPE Values (continued)

LOCALE_IFIRSTWEEKOFYEAR Specifier for the first week of the year. The specifier can be one of these values:

Table 25-39:  LOCALE_IFIRSTWEEKOFYEAR Values

Value Meaning
0 Week containing 1/1 is the first week of that year.
1 First full week following 1/1 is the first week of that year.
2 First week containing at least 4 days is the first week of that year.

Table 25-40:  LCTYPE Values (continued)

LOCALE_SDAYNAME1 Native long name for Monday.
LOCALE_SDAYNAME2 Native long name for Tuesday.
LOCALE_SDAYNAME3 Native long name for Wednesday.
LOCALE_SDAYNAME4 Native long name for Thursday.
LOCALE_SDAYNAME5 Native long name for Friday.
LOCALE_SDAYNAME6 Native long name for Saturday.
LOCALE_SDAYNAME7 Native long name for Sunday.
LOCALE_SABBREVDAYNAME1 Native abbreviated name for Monday.
LOCALE_SABBREVDAYNAME2 Native abbreviated name for Tuesday.
LOCALE_SABBREVDAYNAME3 Native abbreviated name for Wednesday.
LOCALE_SABBREVDAYNAME4 Native abbreviated name for Thursday.
LOCALE_SABBREVDAYNAME5 Native abbreviated name for Friday.
LOCALE_SABBREVDAYNAME6 Native abbreviated name for Saturday.
LOCALE_SABBREVDAYNAME7 Native abbreviated name for Sunday.
LOCALE_SMONTHNAME1 Native long name for January.
LOCALE_SMONTHNAME2 Native long name for February.
LOCALE_SMONTHNAME3 Native long name for March.
LOCALE_SMONTHNAME4 Native long name for April.
LOCALE_SMONTHNAME5 Native long name for May.
LOCALE_SMONTHNAME6 Native long name for June.
LOCALE_SMONTHNAME7 Native long name for July.
LOCALE_SMONTHNAME8 Native long name for August.
LOCALE_SMONTHNAME9 Native long name for September.
LOCALE_SMONTHNAME10 Native long name for October.
LOCALE_SMONTHNAME11 Native long name for November.
LOCALE_SMONTHNAME12 Native long name for December.
LOCALE_SMONTHNAME13 Native name for 13th month, if exists.
LOCALE_SABBREVMONTHNAME1 Native abbreviated name for January.
LOCALE_SABBREVMONTHNAME2 Native abbreviated name for February.
LOCALE_SABBREVMONTHNAME3 Native abbreviated name for March.
LOCALE_SABBREVMONTHNAME4 Native abbreviated name for April.
LOCALE_SABBREVMONTHNAME5 Native abbreviated name for May.
LOCALE_SABBREVMONTHNAME6 Native abbreviated name for June.
LOCALE_SABBREVMONTHNAME7 Native abbreviated name for July.
LOCALE_SABBREVMONTHNAME8 Native abbreviated name for August.
LOCALE_SABBREVMONTHNAME9 Native abbreviated name for September.
LOCALE_SABBREVMONTHNAME10 Native abbreviated name for October.
LOCALE_SABBREVMONTHNAME11 Native abbreviated name for November.
LOCALE_SABBREVMONTHNAME12 Native abbreviated name for December.
LOCALE_SABBREVMONTHNAME13 Native abbreviated name for 13th month, if exists.
LOCALE_SPOSITIVESIGN String value for the positive sign.
LOCALE_SNEGATIVESIGN String value for the negative sign.
LOCALE_IPOSSIGNPOSN Formatting index for positive values. The maximum number of characters allowed for this string is 2. The index can be one of the following values:

Table 25-41:  LOCALE_IPOSSIGNPOSN Values

Value Meaning
0 Parentheses surround the amount and the monetary symbol.
1 The sign string precedes the amount and the monetary symbol.
2 The sign string succeeds the amount and the monetary symbol.
3 The sign string immediately precedes the monetary symbol.
4 The sign string immediately succeeds the monetary symbol.

Table 25-42:  LCTYPE Values (continued)

LOCALE_INEGSIGNPOSN Formatting index for negative values. This index uses the same values as LOCALE_IPOSSIGNPOSN. The maximum number of characters allowed for this string is 2.
LOCALE_IPOSSYMPRECEDES Position of monetary symbol in a positive monetary value. This value is 1 if the monetary symbol precedes the positive amount, 0 if it follows it. The maximum number of characters allowed for this string is 2.
LOCALE_IPOSSEPBYSPACE Separation of monetary symbol in a positive monetary value. This value is 1 if the monetary symbol is separated by a space from a positive amount, 0 if it is not. The maximum number of characters allowed for this string is 2.
LOCALE_INEGSYMPRECEDES Position of monetary symbol in a negative monetary value. This value is 1 if the monetary symbol precedes the negative amount, 0 if it follows it. The maximum number of characters allowed for this string is 2.
LOCALE_INEGSEPBYSPACE Separation of monetary symbol in a negative monetary value. This value is 1 if the monetary symbol is separated by a space from the negative amount, 0 if it is not. The maximum number of characters allowed for this string is 2.
LOCALE_IPAPERSIZE Default paper size associated with the locale.
LOCALE_NOUSEROVERRIDE This constant may be OR'ed with any other LCTYPE constant in a call to the GetLocaleInfo() function. This always causes the function to bypass any user overrides, and return the system default value for the other LCTYPE specified in the function call, based on the given LCID.

25.8.28    LONG

32-bit signed integer.

typedef long LONG;

25.8.29    LPBC

A pointer to a Bind Context.

typedef [unique] IbindCtx *LPBC;

25.8.30    LPBYTE

Pointer to a BYTE.

typedef unsigned char FAR *LPBYTE;

25.8.31    LPCLSID

A pointer to a class ID.

typedef CLSID *LPCLSID;

25.8.32    LPCOLESTR

A pointer to an OLECHAR array.

typedef [string] const OLECHAR *LPOLESTR;

25.8.33    LPCTSTR

Pointer to a constant null-terminated Unicode or Windows character string.

typedef const TCHAR FAR *LPCTSTR;

25.8.34    LPCWSTR

Pointer to a constant null-terminated Unicode character string.

typedef [string] const WCHAR *LPCWSTR;

25.8.35    LPDWORD

Pointer to a DWORD.

typedef DWORD *LPDWORD;

25.8.36    LPIID

A pointer to an interface identifier.

typedef IID *LPIID;

25.8.37    LPMALLOC

A pointer to an IMalloc() interface.

typedef [unique] IMalloc() *LPMALLOC;

25.8.38    LPMALLOCSPY

A pointer to an IMallocSpy() interface.

typedef [unique] IMallocSpy() *LPMALLOCSPY;

25.8.39    LPMARSHAL

A pointer to an IMarshal() interface.

typedef [unique] IMarshal() *LPMARSHAL;

25.8.40    LPMONIKER

A pointer to an IMoniker() interface.

typedef [unique] IMoniker() *LPMONIKER;

25.8.41    LPOLESTR

A pointer to an OLECHAR array.

typedef [string] OLECHAR *LPOLESTR;

25.8.42    LPRUNNINGOBJECTTABLE

A pointer to the running object table interface.

Typedef [unique] IRunningObjectTable() *LPRUNNINGOBJECTTABLE;

25.8.43    LPSECURITY_ATTRIBUTES

typedef
struct _SECURITY_ATTRIBUTES {
    DWORD nLength;
    [size_is(nLength)] LPVOID lpSecurityDescriptor;
    BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

25.8.44    LPSTR

Pointer to a null-terminated Windows character string.

typedef [string] CHAR *LPSTR;

25.8.45    LPSTREAM

Pointer to an IStream() interface.

typedef [unique] IStream() *LPSTREAM;

25.8.46    LPUNKNOWN

A pointer to an IUnknown() interface.

typedef [unique] IUnknown() *LPUNKNOWN;

25.8.47    LPVOID

Pointer to any type.

typedef void *LPVOID;

25.8.48    LPWORD

Pointer to a WORD.

typedef WORD *LPWORD;

25.8.49    LPWSTR

Pointer to a null-terminated Unicode character string.

typedef [string] WCHAR *LPWSTR;

25.8.50    MEMBERID

Identifies the member in a type description. For IDispatch() interfaces, this is the same as DISPID.

typedef DISPID MEMBERID;

This is a 32-bit integral value in the following format.

Table 25-43:  MEMBERID Format

Bits Value
0 - 15 Offset. Any value is permissible.
16 - 21 The nesting level of this type information in the inheritance hierarchy. For example: interface mydisp : IDispatch. The nesting level of IUnknown() is 0, IDispatch is 1, and MyDisp is 2.
22 - 25 Reserved. Must be zero.
26 - 28 Value of the DISPID.
29 TRUE if this is the member ID for a FUNCDESC; otherwise FALSE.
30 - 31 Must be 01.

Negative IDs are reserved for use by Automation.

25.8.51    OLECHAR

A wide character.

typedef WCHAR OLECHAR;

25.8.52    PFILETIME

typedef
struct _FILETIME
{
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

25.8.53    PHKEY

Pointer to a registry key.

typedef HKEY FAR *PHKEY;

25.8.54    PROPID

A pointer to an unsigned long.

typedef ULONG PROPID;

25.8.55    PROPSPEC

The PROPSPEC structure is used by many of the methods of IPropertyStorage() to specify a property either by its property identifier or the associated string name. The structure and related definitions are defined as follows in the header files:

const ULONG    PRSPEC_LPWSTR = 0
const ULONG    PRSPEC_PROPID = 1
typedef ULONG    PROPID
typedef struct tagPROPSPEC 
{
    ULONG ulKind;        // PRSPEC_LPWSTR or PRSPEC_PROPID
    union 
    {
    PROPID      propid;
    LPOLESTR    lpwstr;
    }
} PROPSPEC

25.8.55.1    Members

ulKind

If ulKind is set to PRSPEC_LPWSTR, lpwstr is used and set to a string name. If ulKind is set to PRSPEC_PROPID, propid is used and set to a property identifier value.

propid

Specifies the value of the property identifier. Use either this value or the following lpwstr, not both.

lpwstr

Specifies the string name of the property as a null-terminated Unicode string.

25.8.55.2    Remarks

Header: Declared in objidl.h.

String names are optional and can be assigned to a set of properties when the property is created with a call to IPropertyStorage::WriteMultiple(), or later, with a call to IPropertyStorage::WritePropertyNames().

Windows NT:

Use version 4.0 or later.

Windows:

Use Windows 95 or later. Available as a redistributable for Windows 95.

Windows CE:

Unsupported.

25.8.56    PROPVARIANT

The PROPVARIANT structure is used in most of the methods of IPropertyStorage() to define the type tag and the value of a property in a property set. There are five members. The first, the value type tag, and the last, the value of the property, are significant. The middle three are reserved for future use. The PROPVARIANT structure is defined as follows:

struct PROPVARIANT{
    VARTYPE        vt;          // value type tag
    WORD           wReserved1;
    WORD           wReserved2;
    WORD           wReserved3;
    union { 
    // none                     // VT_EMPTY, VT_NULL, VT_ILLEGAL
    unsigned char  bVal;        // VT_UI1
    short          iVal;        // VT_I2
    USHORT         uiVal;       // VT_UI2
    long           lVal;        // VT_I4
    ULONG          ulVal;       // VT_UI4
    LARGE_INTEGER  hVal;        // VT_I8
    ULARGE_INTEGER uhVal;       // VT_UI8
    float          fltVal;      // VT_R4
    double         dblVal;      // VT_R8
    CY             cyVal;       // VT_CY
    DATE           date;        // VT_DATE
    BSTR           bstrVal;     // VT_BSTR  
    VARIANT_BOOL   boolVal;        // VT_BOOL
    SCODE          scode;       // VT_ERROR
    FILETIME       filetime;    // VT_FILETIME
    LPSTR          pszVal;      // VT_LPSTR     // string in the current system Ansi code page
    LPWSTR         pwszVal;     // VT_LPWSTR    // string in Unicode
    CLSID*         puuid;       // VT_CLSID
    CLIPDATA*      pclipdata;   // VT_CF
    BLOB           blob;        // VT_BLOB, VT_BLOBOBJECT
    IStream*       pStream;     // VT_STREAM, VT_STREAMED_OBJECT
    IStorage*      pStorage;    // VT_STORAGE, VT_STORED_OBJECT
    CAUB           caub;         // VT_VECTOR | VT_UI1
    CAI            cai;          // VT_VECTOR | VT_I2
    CAUI           caui;         // VT_VECTOR | VT_UI2
    CAL            cal;          // VT_VECTOR | VT_I4
    CAUL           caul;         // VT_VECTOR | VT_UI4
    CAH            cah;          // VT_VECTOR | VT_I8
    CAUH           cauh;         // VT_VECTOR | VT_UI8
    CAFLT          caflt;        // VT_VECTOR | VT_R4
    CADBL          cadbl;        // VT_VECTOR | VT_R8
    CACY           cacy;         // VT_VECTOR | VT_CY
    CADATE         cadate;       // VT_VECTOR | VT_DATE
    CABSTR         cabstr;       // VT_VECTOR | VT_BSTR
    CABOOL         cabool;       // VT_VECTOR | VT_BOOL
    CASCODE        cascode;      // VT_VECTOR | VT_ERROR
    CALPSTR        calpstr;      // VT_VECTOR | VT_LPSTR
    CALPWSTR       calpwstr;     // VT_VECTOR | VT_LPWSTR
    CAFILETIME     cafiletime;   // VT_VECTOR | VT_FILETIME
    CACLSID        cauuid;       // VT_VECTOR | VT_CLSID
    CACLIPDATA     caclipdata;   // VT_VECTOR | VT_CF
    CAPROPVARIANT  capropvar;    // VT_VECTOR | VT_VARIANT
    }} PROPVARIANT

The bool member in previous definitions of this structure has been renamed to boolVal, since some compilers now recognize bool as a keyword.

25.8.56.1    Remarks

Header: Declared in objidl.h.

PROPVARIANT is the fundamental data type by which property values are read and written through the IPropertyStorage() interface. The data type PROPVARIANT is related to the data type VARIANT, defined as part of Automation in OLE2 and defined in the Win32 SDK header file oleauto.h. Several definitions are reused from Automation, as follows:

typedef struct  tagCY {
    unsigned long      Lo;
    long               Hi;
    } CY
typedef CY             CURRENCY;
typedef short          VARIANT_BOOL;
typedef unsigned short VARTYPE;
typedef double         DATE;
typedef OLECHAR*       BSTR;
typedef struct         tagCLIPDATA {
    ULONG              cbSize;  //Includes sizeof(ulClipFmt)
    long               ulClipFmt;
    BYTE*              pClipData;
    } CLIPDATA

In addition, several new data types that define counted arrays of other data types are required. The data types of all counted arrays begin with the letters CA (such as CAUB) and have an ORed vt value. The counted array structure has the following form (where name is the specific name of the counted array):

#define TYPEDEF_CA(type, name) 
    typedef struct tag ## name {\
        ULONG cElems;\
        type *pElems;\
        } name

Table 25-44:  PROPVARIANT Types

Propvariant Type Code Propvariant Member Value Representation
VT_EMPTY 0 None A property with a type indicator of VT_EMPTY has no data associated with it; that is, the size of the value is zero.
VT_NULL 1 None This is like a pointer to NULL.
VT_UI1 17 bVal 1-byte unsigned integer
VT_I2 2 iVal Two bytes representing a 2-byte signed integer value.
VT_UI2 18 uiVal 2-byte unsigned integer
VT_I4 3 lVal 4-byte signed integer value
VT_UI4 19 ulVal 4-byte unsigned integer
VT_I8 20 hVal 8-byte signed integer
VT_UI8 21 uhVal 8-byte unsigned integer
VT_R4 4 fltVal 32-bit IEEE floating point value
VT_R8 5 dblVal 64-bit IEEE floating point value
VT_CY 6 cyVal 8-byte two's complement integer (scaled by 10,000). This type is commonly used for currency amounts.
VT_DATE 7 date A 64-bit floating point number representing the number of days (not seconds) since December 31, 1899. For example, January 1, 1900 is 2.0, January 2, 1900 is 3.0, and so on). This is stored in the same representation as VT_R8.
VT_BSTR 8 bstrVal Pointer to a null terminated Unicode string. The string is immediately preceded by a DWORD representing the byte count, but bstrVal points past this DWORD to the first character of the string. BSTRs must be allocated and freed using the OLE Automation SysAllocString() and SysFreeString() calls.
VT_BOOL 11 boolVal (bool in earlier designs) Boolean value, a WORD containing 0 (false) or -1 (true).
VT_ERROR 10 scode A DWORD containing a status code.
VT_FILETIME 64 filetime 64-bit FILETIME structure as defined by Win32. It is recommended that all times be stored in Universal Coordinate Time (UTC).
VT_LPSTR 30 pszVal Pointer to a null terminated ANSI string in the system default code page.
VT_LPWSTR 31 pwszVal Pointer to a null terminated Unicode string in the user's default locale.
VT_CLSID 72 puuid Pointer to a CLSID (or other GUID).
VT_CF 71 pclipdata Pointer to a CLIPDATA structure, described above.
VT_BLOB 65 blob DWORD count of bytes, followed by that many bytes of data. The byte count does not include the four bytes for the length of the count itself; an empty BLOB would have a count of zero, followed by zero bytes. This is similar to VT_BSTR but does not guarantee a null byte at the end of the data.
VT_BLOBOBJECT 70 blob A BLOB containing a serialized object in the same representation as would appear in a VT_STREAMED_OBJECT. That is, a DWORD byte count (where the byte count does not include the size of itself) which is in the format of a class identifier followed by initialization data for that class. The only significant difference between VT_BLOB_OBJECT and VT_STREAMED_OBJECT is that the former does not have the system-level storage overhead that the latter would have, and is therefore more suitable for scenarios involving numbers of small objects.
VT_STREAM 66 pStream Pointer to an IStream() interface, representing a stream which is a sibling to the "Contents" stream.
VT_STREAMED_OBJECT 68 pStream As in VT_STREAM, but indicates that the stream contains a serialized object, which is a CLSID followed by initialization data for the class. The stream is a sibling to the Contents stream that contains the property set.
VT_STORAGE 67 pStorage Pointer to an IStorage() interface, representing a storage object that is a sibling to the ``Contents'' stream.
VT_STORED_OBJECT 69 pStorage As in VT_STORAGE, but indicates that the designated IStorage() contains a loadable object.
VT_VECTOR 0x1000 ca* If the type indicator is one of the simple propvariant types ORed with this one, the value is one of the counted array values. This is a DWORD count of elements, followed by that many repetitions of the value. For example, a type indicator of VT_LPSTR|VT_VECTOR has a DWORD element count, a DWORD byte count, the first string data, padding bytes for 32-bit alignment (see below), a DWORD byte count, the second string data, and so on. Nonsimple types cannot be ORed with VT_VECTOR. These types are VT_STREAM, VT_STREAM_OBJECT, VT_STORAGE, VT_STORAGE_OBJECT. VT_BLOB and VT_BLOB_OBJECT types also cannot be ORed with VT_VECTOR.
VT_VARIANT 12 capropvar A DWORD type indicator followed by the corresponding value. VT_VARIANT can be used only with VT_VECTOR.
VT_TYPEMASK 0xFFF Used as a mask for VT_VECTOR and other modifiers to extract the raw VT value.

Clipboard format identifiers, stored with the tag VT_CF, use one of five different representations (identified in the ulClipFmt member of the CLIPDATA structure):

Table 25-45:  Clipboard Format Identifiers

ulClipFmt Value pClipData value
-1L a DWORD containing a built-in Windows clipboard format value.
-2L a DWORD containing a Macintosh clipboard format value.
-3L a GUID containing a format identifier (rarely used).
any positive value a null-terminated string containing a Windows clipboard format name, one suitable for passing to RegisterClipboardFormat. The code page used for characters in the string is per the code page indicator. The "positive value" here is the length of the string, including the null byte at the end.
0L no data (rarely used)

Within a vector of values, each repetition of a value is to be aligned to 32-bit boundaries. The exception to this rule is scalar types which are less than 32 bits: VT_UI1, VT_12, VT_U12, and VT_BOOL. Vectors of these values are packed. Therefore, a value with type tag VT_I2 | VT_VECTOR would be a DWORD element count, followed by a sequence of packed 2-byte integers with no padding between them. However, a value with type tag VT_LPSTR | VT_VECTOR would be a DWORD element count, followed by a sequence of (DWORD cch, char rgch[]) strings, each of which may be followed by null padding to round to a 32-bit boundary.

Windows NT:

Use version 4.0 or later.

Windows:

Use Windows 95 or later. Available as a redistributable for Windows 95.

Windows CE:

Unsupported.

25.8.57    PSECURITY_DESCRIPTOR

A pointer to a security descriptor.

typedef PVOID PSECURITY_DESCRIPTOR;

25.8.58    PULONG

Pointer to an unsigned long (32 bits).

typedef ULONG *PULONG;

25.8.59    PVALENT

typedef
struct value_entA {
    LPSTR   ve_valuename;
    DWORD ve_valuelen;
    DWORD ve_valueptr;
    DWORD ve_type;
}VALENTA, FAR *PVALENTA;
typedef struct value_entW {
    LPWSTR  ve_valuename;
    DWORD ve_valuelen;
    DWORD ve_valueptr;
    DWORD ve_type;
}VALENTW, FAR *PVALENTW;
#ifdef UNICODE
typedef VALENTW VALENT;
typedef PVALENTW PVALENT;
#else
typedef VALENTA VALENT;
typedef PVALENTA PVALENT;
#endif // UNICODE

25.8.60    PVOID

Pointer to any type.

typedef void *PVOID;

25.8.61    PWCHAR

Pointer to a Unicode character.

typedef WCHAR *PWCHAR;

25.8.62    REFCLSID

A pointer to a class ID.

typedef CLSID *REFCLSID;

25.8.63    REFFMTID

A pointer to an FMTID.

typedef FMTID *REFFMTID;

25.8.64    REFGUID

A pointer to a globally unique identifier.

typedef GUID *REFGUID;

25.8.65    REFIID

A pointer to an interface identifier.

typedef IID *REFIID;

25.8.66    REGKIND

Controls how a type library is registered. It is defined as follows:

typedef enum tagREGKIND{
    REGKIND_DEFAULT,
    REGKIND_REGISTER,
    REGKIND_NONE
} REGKIND;

Table 25-46:  REGKIND Values

Value Description
REGKIND_DEFAULT Use default register behavior
REGKIND_REGISTER Registered type
REGKIND_NONE Not a registered type

25.8.67    REGSAM

Data type used for specifying the security access attributes in the registry. A REGSAM value can be one or more of the following values:

KEY_ALL_ACCESS

Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_SUB_KEY, KEY_CREATE_LINK, and KEY_SET_VALUE access.

KEY_CREATE_LINK

Permission to create a symbolic link.

KEY_CREATE_SUB_KEY

Permission to create subkeys.

KEY_ENUMERATE_SUB_KEYS

Permission to enumerate subkeys.

KEY_EXECUTE

Permission for read access.

KEY_NOTIFY

Permission for change notification.

KEY_QUERY_VALUE

Permission to query subkey data.

KEY_READ

Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY access.

KEY_SET_VALUE

Permission to set subkey data.

KEY_WRITE

Combination of KEY_SET and KEY_CREATE_SUB_KEY access.

25.8.68    RPC_AUTH_IDENTITY_HANDLE

typedef
void * RPC_AUTH_IDENTITY_HANDLE;

An identity handle points to the data structure that contains the client's authentication and authorization credentials specified for remote procedure calls.

25.8.69    RPC_AUTHZ_HANDLE

A pointer to the authorization service.

typedef void __RPC_FAR *RPC_AUTHZ_HANDLE;

25.8.70    RPC_FAR

Defined to nothing.

#define RPC_FAR

25.8.71    RPCOLEMESSAGE

typedef
struct tagRPCOLEMESSAGE
    {
        void             *reserved1;
        RPCOLEDATAREP     dataRepresentation;
        void             *Buffer;
        ULONG             cbBuffer;
        ULONG             iMethod;
        void             *reserved2[5];
        ULONG             rpcFlags;
    } RPCOLEMESSAGE;

25.8.72    SECURITY_INFORMATION

Header: Declared in winnt.h.

The SECURITY_INFORMATION structure identifies the object-related security information being set or queried. This security information includes:

Table 25-47:  Security Information Bit Flags

Value Meaning
OWNER_SECURITY_INFORMATION Indicates the owner identifier of the object is being referenced.
GROUP_SECURITY_INFORMATION Indicates the primary group identifier of the object is being referenced.
DACL_SECURITY_INFORMATION Indicates the discretionary ACL of the object is being referenced.
SACL_SECURITY_INFORMATION Indicates the system ACL of the object is being referenced.

Windows NT:

Use version 3.1 or later.

Windows:

Unsupported.

Windows CE:

Unsupported.

25.8.73    SIZEL

typedef
struct tagSIZEL
{
    LONG cx;
    LONG cy;
} SIZEL, *PSIZEL, *LPSIZEL;

25.8.74    SOLE_AUTHENTICATION_SERVICE

Header: Declared in objidl.h.

Identifies an authentication service. This structure is retrieved through a call to CoQueryAuthenticationServices(), and passed in to CoInitializeSecurity().

typedef struct tagSOLE_AUTHENTICATION_SERVICE {
        DWORD       dwAuthnSvc;
        DWORD       dwAuthzSvc;
        OLECHAR*    pPrincipalName;
        HRESULT     hr;
    } SOLE_AUTHENTICATION_SERVICE;

25.8.74.1    Members

dwAuthnSvc

The authentication service. It may contain a single value taken from the list of RPC_C_AUTHN_xxx constants defined in rpcdce.h. RPC_C_AUTHN_NONE turns off authentication. On Win32, RPC_C_AUTHN_DEFAULT causes COM to use the RPC_C_AUTHN_WINNT authentication.

dwAuthzSvc

The authorization service. It may contain a single value taken from the list of RPC_C_AUTHZ_xxx constants defined in rpcdce.h. The validity and trustworthiness of authorization data, like any application data, depends on the authentication service and authentication level selected. This parameter is ignored when using the RPC_C_AUTHN_WINNT authentication service.

pPrincipalName

Principal name to be used with the authentication service. If the principal name is NULL, COM assumes the current user identifier. A NULL principal name is allowed for NTLM SSP and Kerberos authentication services, but may not work for other authentication services.

hr

When used in CoInitializeSecurity(), set on return to indicate the status of the call to register the authentication services.

Windows NT:

Use version 4.0 or later.

Windows:

Use Windows 95 or later. Available as a redistributable for Windows 95.

Windows CE:

Unsupported.

25.8.75    STDAPI

Standard API calling convention.

#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE

25.8.76    SYSKIND

Identifies the target operating system platform. It is defined as follows:

typedef enum tagSYSKIND {
    SYS_WIN16,
    SYS_WIN32,
    SYS_MAC
} SYSKIND;

Table 25-48:  SYSKIND Values

Value Description
SYS_WIN16 The target operating system for the type library is 16-bit Windows systems. By default, data members are packed.
SYS_WIN32 The target operating system for the type library is 32-bit Windows systems. By default, data members are naturally aligned (for example, 2-byte integers are aligned on even-byte boundaries; 4-byte integers are aligned on quad-word boundaries, and so on).
SYS_MAC The target operating system for the type library is Apple Macintosh. By default, all data members are aligned on even-byte boundaries.

25.8.77    SYSTEMTIME

The SYSTEMTIME structure has the following form:

typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
} SYSTEMTIME;

The SYSTEMTIME structure represents a date and time using individual members for the month, day, year, weekday, hour, minute, second, and millisecond:

wYear

The current year.

wMonth

The current month; January is 1.

wDayOfWeek

The current day of the week; Sunday is 0, Monday is 1, and so on.

wDay

The current day of the month.

wHour

The current hour.

wMinute

The current minute.

wSecond

The current second.

wMilliseconds

The current millisecond.

25.8.78    TLIBATTR

Contains information about a type library. Information from this structure is used to identify the type library and to provide national language support for member names. It is defined as follows:

typedef struct FARSTRUCT tagTLIBATTR {
    GUID guid;                      // Unique ID of the library.
    LCID lcid;                      // Language/locale of the library.
    SYSKIND syskind;                // Target hardware platform.
    unsigned short wMajorVerNum;    // Major version number.
    unsigned short wMinorVerNum;    // Minor version number.
    unsigned short wLibFlags;       // Library flags.
} TLIBATTR, FAR * LPTLIBATTR;

25.8.79    TYPEATTR

Contains attributes of an ITypeInfo(), and is defined as follows:

typedef struct FARSTRUCT tagTYPEATTR {
    GUID guid;                    // The GUID of the type information.
    LCID lcid;                    // Locale of member names and doc
                                  // strings.
    unsigned long dwReserved;
    MEMBERID memidConstructor;    // ID of constructor, or MEMBERID_NIL if
                                  // none.
    MEMBERID memidDestructor;     // ID of destructor, or MEMBERID_NIL if
                                  // none. 
    OLECHAR FAR* lpstrSchema;     // Reserved for future use.
    unsigned long cbSizeInstance; // The size of an instance of 
                                  // this type.
    TYPEKIND typekind;            // The kind of type this information
                                  // describes.
    unsigned short cFuncs;        // Number of functions.
    unsigned short cVars;         // Number of variables/data members.
    unsigned short cImplTypes;    // Number of implemented interfaces.
    unsigned short cbSizeVft;     // The size of this type's VTBL.
    unsigned short cbAlignment;   // Byte alignment for an instance
                                  // of this type.
    unsigned short wTypeFlags;
    unsigned short wMajorVerNum;  // Major version number.
    unsigned short wMinorVerNum;  // Minor version number.
    TYPEDESC tdescAlias;          // If TypeKind == TKIND_ALIAS, 
                                  // specifies the type for which 
                                  // this type is an alias.
    IDLDESC idldescType;          // IDL attributes of the 
                                  // described type.
} TYPEATTR, FAR* LPTYPEATTR;

The cbAlignment field indicates how addresses are aligned. A value of 0 indicates alignment on the 64K boundary; 1 indicates no special alignment. For other values, n indicates aligned on byte n.

25.8.80    UINT

Unsigned integer.

typedef unsigned int UINT;

25.8.81    ULARGE_INTEGER

Header: Declared in winnt.h.

The ULARGE_INTEGER structure is used to specify a 64-bit unsigned integer value.

typedef union _ULARGE_INTEGER { 
    struct {
        DWORD LowPart; 
        DWORD HighPart; 
    };
    DWORDLONG QuadPart;
} ULARGE_INTEGER;

25.8.81.1    Members

The ULARGE_INTEGER structure is actually a union. If your compiler has built-in support for 64-bit integers, use the QuadPart member to store the 64-bit integer. Otherwise, use the LowPart and HighPart members to store the 64-bit integer.

LowPart

Specifies the low-order 32 bits.

HighPart

Specifies the high-order 32 bits.

QuadPart

Specifies a 64-bit unsigned integer.

Windows NT:

Use version 3.1 or later.

Windows:

Use Windows 95 or later.

Windows CE:

Use version 1.0 or later.

25.8.82    ULONG

Unsigned long integer.

typedef DWORD ULONG;

25.8.83    USHORT

Unsigned short integer.

typedef unsigned short USHORT;

25.8.84    VARDESC

Describes a variable, constant, or data member. It is defined as follows:

typedef struct FARSTRUCT tagVARDESC {
    MEMBERID memid;
    OLECHAR FAR* lpstrSchema;    // Reserved for future use.
    union {
                                 // VAR_PERINSTANCE, the offset of this
                                 // variable within the instance.
    unsigned long oInst;
                                 // VAR_CONST, the value of the constant.
    VARIANT FAR* lpvarValue;
    } UNION_NAME(u);
    ELEMDESC elemdescVar;
    unsigned short wVarFlags;
    VARKIND varkind;
} VARDESC

25.8.85    VARIANT and VARIANTARG

Use VARIANTARG to describe arguments passed within DISPPARAMS, and VARIANT to specify variant data that cannot be passed by reference. The VARIANT type cannot have the VT_BYREF bit set. VARIANTs can be passed by value, even if VARIANTARGs cannot.

typedef struct FARSTRUCT tagVARIANT VARIANT;
typedef struct FARSTRUCT tagVARIANT VARIANTARG;
typedef struct tagVARIANT  {
    VARTYPE vt;
    unsigned short wReserved1;
    unsigned short wReserved2;
    unsigned short wReserved3;
    union {
        unsigned char    bVal;             // VT_UI1.
        short            iVal;             // VT_I2.
        long             lVal;             // VT_I4.
        float            fltVal;           // VT_R4.
        double           dblVal;           // VT_R8.
        VARIANT_BOOL     boolVal;          // VT_BOOL.
        SCODE            scode;            // VT_ERROR.
        CY               cyVal;            // VT_CY.
        DATE             date;             // VT_DATE.
        BSTR             bstrVal;          // VT_BSTR.
        IUnknown         FAR* punkVal;     // VT_UNKNOWN.
        IDispatch        FAR* pdispVal;    // VT_DISPATCH.
        SAFEARRAY        FAR* parray;      // VT_ARRAY|*.
        unsigned char    FAR* pbVal;       // VT_BYREF|VT_UI1.
        short            FAR* piVal;       // VT_BYREF|VT_I2.
        long             FAR* plVal;       // VT_BYREF|VT_I4.
        float            FAR* pfltVal;     // VT_BYREF|VT_R4.
        double           FAR* pdblVal;     // VT_BYREF|VT_R8.
        VARIANT_BOOL     FAR* pboolVal;    // VT_BYREF|VT_BOOL.
        SCODE            FAR* pscode;      // VT_BYREF|VT_ERROR.
        CY               FAR* pcyVal;      // VT_BYREF|VT_CY.
        DATE             FAR* pdate;       // VT_BYREF|VT_DATE.
        BSTR             FAR* pbstrVal;    // VT_BYREF|VT_BSTR.
        IUnknown FAR*    FAR* ppunkVal;    // VT_BYREF|VT_UNKNOWN.
        IDispatch FAR*   FAR* ppdispVal;   // VT_BYREF|VT_DISPATCH.
        SAFEARRAY FAR*   FAR* pparray;     // VT_ARRAY|*.
        VARIANT          FAR* pvarVal;     // VT_BYREF|VT_VARIANT.
        void             FAR* byref;       // GenericByRef.
    };
};

To simplify extracting values from VARIANTARGs, Automation provides a set of functions for manipulating this type. Use of these functions is strongly recommended to ensure that applications apply consistent coercion rules. The vt value governs the interpretation of the union as follows:

Table 25-49:  tagVARIANT vt Values

Value Description
VT_EMPTY No value was specified. If an optional argument to an Automation method is left blank, do not pass a VARIANT of type VT_EMPTY. Instead, pass a VARIANT of type VT_ERROR with a value of DISP_E_PARAMNOTFOUND.
VT_EMPTY | VT_BYREF Not valid.
VT_UI1 An unsigned 1-byte character is stored in bVal.
VT_UI1 | VT_BYREF A reference to an unsigned 1-byte character was passed. A pointer to the value is in pbVal.
VT_I2 A 2-byte integer value is stored in iVal.
VT_I2 | VT_BYREF A reference to a 2-byte integer was passed. A pointer to the value is in piVal.
VT_I4 A 4-byte integer value is stored in lVal.
VT_I4 | VT_BYREF A reference to a 4-byte integer was passed. A pointer to the value is in plVal.
VT_R4 An IEEE 4-byte real value is stored infltVal.
VT_R4 | VT_BYREF A reference to an IEEE 4-byte real value was passed. A pointer to the value is in pfltVal.
VT_R8 An 8-byte IEEE real value is stored in dblVal.
VT_R8 | VT_BYREF A reference to an 8-byte IEEE real value was passed. A pointer to its value is in pdblVal.
VT_CY A currency value was specified. A currency number is stored as an 8-byte, two's complement integer, scaled by 10,000 to give a fixed-point number with 15 digits to the left of the decimal point and 4 digits to the right. The value is in cyVal.
VT_CY | VT_BYREF A reference to a currency value was passed. A pointer to the value is in pcyVal.
VT_BSTR A string was passed; it is stored in bstrVal. This pointer must be obtained and freed by the BSTR functions.
VT_BSTR | VT_BYREF A reference to a string was passed. A BSTR* that points to a BSTR is in pbstrVal. The referenced pointer must be obtained or freed by the BSTR functions.
VT_NULL A propagating null value was specified. (This should not be confused with the null pointer.) The null value is used for tri-state logic, as with SQL.
VT_NULL | VT_BYREF Not valid.
VT_ERROR An SCODE was specified. The type of the error is specified in scodee. Generally, operations on error values should raise an exception or propagate the error to the return value, as appropriate.
VT_ERROR | VT_BYREF A reference to an SCODE was passed. A pointer to the value is in pscode.
VT_BOOL A Boolean (TRUE/FALSE) value was specified. A value of 0xFFFF (all bits 1) indicates TRUE; a value of 0 (all bits 0) indicates FALSE. No other values are valid.
VT_BOOL | VT_BYREF A reference to a Boolean value. A pointer to the Boolean value is in pbool.
VT_DATE A value denoting a date and time was specified. Dates are represented as double-precision numbers, where midnight, January 1, 1900 is 2.0, January 2, 1900 is 3.0, and so on. The value is passed in date. This is the same numbering system used by most spreadsheet programs, although some specify incorrectly that February 29, 1900 existed, and thus set January 1, 1900 to 1.0. The date can be converted to and from an MS-DOS representation using VariantTimeToDosDateTime().
VT_DATE | VT_BYREF A reference to a date was passed. A pointer to the value is in pdate.
VT_DISPATCH A pointer to an object was specified. The pointer is in pdispVal. This object is known only to implement IDispatch(). The object can be queried as to whether it supports any other desired interface by calling QueryInterface() on the object. Objects that do not implement IDispatch() should be passed using VT_UNKNOWN.
VT_DISPATCH | VT_BYREF A pointer to a pointer to an object was specified. The pointer to the object is stored in the location referred to by ppdispVal.
VT_VARIANT Invalid. VARIANTARGs must be passed by reference.
VT_VARIANT | VT_BYREF A pointer to another VARIANTARG is passed in pvarVal. This referenced VARIANTARG will never have the VT_BYREF bit set in vt, so only one level of indirection can ever be present. This value can be used to support languages that allow functions to change the types of variables passed by reference.
VT_UNKNOWN A pointer to an object that implements the IUnknown() interface is passed in punkVal.
VT_UNKNOWN | VT_BYREF A pointer to the IUnknown() interface is passed in ppunkVal. The pointer to the interface is stored in the location referred to by ppunkVal.
VT_ARRAY | <anything> An array of data type <anything> was passed. (VT_EMPTY and VT_NULL are invalid types to combine with VT_ARRAY.) The pointer in pbyrefVal points to an array descriptor, which describes the dimensions, size, and in-memory location of the array. The array descriptor is never accessed directly.

25.8.86    VARTYPE

An enumeration type used in VARIANT, TYPEDESC, OLE property sets, and safe arrays. The enumeration constants listed in the following VARENUM section are valid in the vt field of a VARIANT structure.

typedef unsigned short VARTYPE;
enum VARENUM{
    VT_EMPTY     = 0,             // Not specified.
    VT_NULL      = 1,             // Null.
    VT_I2        = 2,             // 2-byte signed int.
    VT_I4        = 3,             // 4-byte signed int.
    VT_R4        = 4,             // 4-byte real.
    VT_R8        = 5,             // 8-byte real.
    VT_CY        = 6,             // Currency.
    VT_DATE      = 7,             // Date.
    VT_BSTR      = 8,             // Binary string.
    VT_DISPATCH  = 9,             // IDispatch
    VT_ERROR     = 10,            // Scodes.
    VT_BOOL      = 11,            // Boolean; True=-1, False=0.
    VT_VARIANT   = 12,            // VARIANT FAR*.
    VT_UNKNOWN   = 13,            // IUnknown FAR*.
    VT_UI1       = 17,            // Unsigned char.
    // Other constants that are not valid in VARIANTs omitted here.
};
    VT_RESERVED  = (int) 0x8000
    // By reference, a pointer to the data is passed.
    VT_BYREF     = (int) 0x4000    
    VT_ARRAY     = (int) 0x2000   // A safe array of the data is passed.

25.8.87    VOID

Any type.

#define VOID void

25.8.88    WCHAR

Unicode character.

typedef wchar_t WCHAR

25.8.89    WINAPI

Calling convention for the Win32 API.

#define WINAPI     FAR PASCAL

25.8.90    WINOLEAPI

Calling convention for the Windows OLE API.

#define WINOLEAPI    STDAPI

25.8.91    WORD

16-bit unsigned integer.

typedef unsigned short WORD;