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:
Credential Management APIs--Credential Management APIs provide access to credentials (password data, tickets, and so on) of a principal or free such access. The APIs are:
AcquireCredentialsHandle
--This method
acquires a handle to the reference credentials.
FreeCredentialsHandle
--This method
releases a credential handle and associated resources.
QueryCredentialAttributes
--This method
allows queries on various credential attributes like associated name, domain
name, and so forth.
Context Management APIs--Context management APIs provide methods for creating and using security contexts. The contexts are created on both the client and the server side of a communication link. These contexts can then be used later with the message support APIs. The APIs are:
InitializeSecurityContext
--Initiates
a security context by generating an opaque message (security token) that can
be passed to the server.
AcceptSecurityContext
--Creates a security
context using the opaque message received from the client.
DeleteSecurityContext
--Frees a security
context and associated
resources.
QueryContextAttributes
--Allows queries
on various context attributes.
ApplyControlToken
--Applies a supplemental
security message to an existing
security context.
CompleteAuthToken
--Completes an authentication
token, since some protocols,
like DCE RPC, need to revise the security information once the transport has
updated some message fields.
ImpersonateSecurityContext
--Attaches
the client's security context as an
impersonation token to the calling thread.
RevertSecurityContext
--Ceases impersonation
and defaults the calling thread
to its primary token.
Message Support APIs--Message support APIs provide communication integrity and privacy services based on a security context. The APIs are:
MakeSignature
--Generates a secure
signature based on a message and a security
context.
VerifySignature
--Verifies that the
signature matches a received message.
Package Management APIs--Package Managment APIs provide services for different security packages that the security provider supports. The APIs are:
EnumerateSecurityPackages
--Lists available
security packages and
their capabilities.
QuerySecurityPackageInfo
--Queries
an individual security package for its
capabilities.
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.
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:
Authentication-related capabilities:
Client-only authentication
Multileg authentication required
Transport-related capabilities:
Datagram-style transports
Connection-oriented transports
Data stream connection semantics
Message-related capabilities:
Supports message integrity
Supports message privacy
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.
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:
Initializing the SSPI
Establishing an authenticated connection
Ensuring communication integrity during message exchange
``Security quality of service'' to service a client request
These stages are described in the following sections.
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:
Load the security provider DLL
Get a pointer to the provider initialization function
Use the initialization function to get a reference to the provider's security function table
Get specific information about the security package, such as the maximum token size
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.
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 //
NTLM
MSN
Schannel (SSL/ Private Communications Technology [PCT])
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.
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;
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;
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:
Server should be able to authenticate the client.
Client should be able to authenticate the server.
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.
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:
AcquireCredentialsHandle
to obtain a reference
to previously obtained logon
credentials
InitializeSecurityContext
to create the
initial authentication request
security tokens
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:
Arg1
= Principal Name, set to
NULL
here to let the
security package use the default.
Arg2 = Security Package Name, set to the one that was selected during package setup.
Arg3 = Type of credential, the client will use outbound credentials.
Arg4
= Pointer to
LogonID
,
set to
NULL
to let the security package use the default.
Arg5
=
AuthIdentity
,
set to
NULL
to use the process's default credentials.
This parameter may be used to provide.
package specific data.
For an NTLM
security package it may contain a pointer to the
SEC_WINNT_AUTH_IDENTIY
structure that contains the username, domainname, and password.
This feature
is
used, for example, by file system redirectors to allow users to specify an
alternate account name than the one they are currently logged in as when
connecting to a remote file server.
Arg6
=
GetKey
function,
set to
NULL
,
not used.
Arg7
= Any argument to the
GetKey
function, also
set to
NULL
.
Arg8 = returned Credentials Handle, used for additional SSPI calls.
Arg9
= returned
TimeStamp
which indicates the
lifespan of the credentials
handle.
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:
Arg1
= Credentials handle received from
AcquireCredentialsHandle
call.
Arg2 = Old Context handle if any.
Arg3
= Target server name, which is ignored
by NTLM
SSP
.
Arg4
= Context Attributes Requested (See
SSPI.H
for valid values).
Arg5 = Reserved Parameter.
Arg6
= Data Representation (see
SSPI.H
for valid values).
Arg7 = Input Buffer Descriptor (if there is one received from the server).
Arg8 = Reserved Parameter.
Arg9 = New Context Handle.
Arg10 = Output Buffer Descriptor (contains what will be sent to the server).
Arg11 = Context Attributes that are supported by the provider.
Arg12
=
TimeStamp
for the lifespan of context validity.
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.
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:
Arg1
= Principal Name, set to
NULL
here to let the
security package use the default
Arg2 = Security Package Name, set to the one that was selected at initialization
Arg3
= Type of credentials, inbound for
a server, use
SECPKG_CRED_BOTH
if
this server is going to be a client to another server.
Arg4
= Pointer to
LogonID
(set to
NULL
to let the security package use the default).
Arg5
=
AuthIdentity
Package specific authentication data.
Since NTLM does not support server authentication, this can be
NULL
.
For other
security providers, this can be server authentication data, such as public
key credentials.
Arg6
=
GetKey
function
(set to
NULL
)
Arg7
= Any argument to the
GetKey
function (also
set to
NULL
)
Arg8 = Returned Credentials Handle.
Arg9
= Returned
TimeStamp
which indicates the life
span of the credentials handle.
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:
Arg1
= Credentials handle returned from
the
AcquireCredentialsHandle
call.
Arg2 = Old Context handle if any.
Arg3 = Input Buffer Descriptor (if there is one received from client).
Arg4 = Context Attributes Requested (See Section 25.7.5 below for more information).
Arg5
= Data Representation (see
SSPI.H
for valid values).
Arg6 = New Context Handle.
Arg7 = Output Buffer Descriptor, containing what will be sent back to the client.
Arg8 = Context Attributes that are supported by the provider.
Arg9
=
TimeStamp
for
the lifespan of context validity.
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!!).
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.
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.
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:
MakeSignature
--Generates a secure
signature based on a message and a security
context.
VerifySignature
--Verifies that the
signature matches a received message.
The message APIs provide integrity for application data messages.
MakeSignature
generates a checksum of the message and also includes sequencing information
to
prevent message loss or insertion.
The next sections show how the sender and
receiver use the SSPI Message APIs.
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:
Arg1 = Context Handle for the active security context
Arg2 = Quality of protection
Arg3 = Buffer descriptor containing the message for signing.
Arg4 = Sequence number of the message if sequence detection is on.
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.
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:
Arg1 = Context Handle for the active context
Arg2 = Buffer descriptor containing received message
Arg3 = Sequence number expected for the received message
Arg4 = Quality of protection on the message (if any)
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.
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. //
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. //
The Security Support Provider Interface model supports three types of security contexts, which are summarized in the following table.
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. |
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.
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:
The security package does not produce an authentication blob
(binary large
object) on the first call to the
InitializeSecurityContext
function.
However,
the client can immediately use the returned security context in a call to
the
MakeSignature
function to generate a signature for a message.
The security package must allow for the context to be re-established
multiple times to allow the server to drop the connection without notice.
This
also implies that any keys used in the
MakeSignature
and
VerifySignature
functions can be reset to a consistent state.
The security package must allow for the caller to specify sequence information, and must provide it back again at the other end. This is not exclusive of any sequence information maintained by the package and can be viewed as a special payload.
A security package sets the
SECPKG_FLAG_DATAGRAM
flag to
indicate that it supports datagram semantics.
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:
The package sets the
SECPKG_FLAG_STREAM
flag to indicate that it supports
stream semantics, just as it would set a flag to indicate support for
connection and datagram semantics.
A transport application requests stream semantics by setting
the
ISC_REQ_STREAM
and
ASC_REQ_STREAM
flags
in the calls to the
InitializeSecurityContext
and
AcceptSecurityContext
functions.
The application calls the
QueryContextAttributes
function with a
SecPkgContext_StreamSizes
structure to query the security
context for the
number of buffers to provide, and the sizes to reserve for headers or trailers.
The application provides buffer descriptors to spare during the actual processing of the data.
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:
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:
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.
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.
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. |
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;
Boolean variable (should be
TRUE
or
FALSE
).
Header file: |
WTYPES.H |
A length-prefixed string used by Automation data manipulation functions.
typedef OLECHAR *BSTR;
BSTR
s 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;
BYTE
is an unsigned character data type that is binary data.
Header file: | WINDEF.H |
typedef unsigned char BYTE;
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;
Variable that remains constant during an execution.
Header file: | WTYPES.H |
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 |
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:
DISPID_Name-800
DISPID_Delete-801
DISPID_Object-802
DISPID_Parent-803
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;
A 32-bit unsigned integer or the address of a segment and its associated offset.
Header file: | WTYPES.H |
#define far #define FAR far
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:
A value of 0 specifies that no optional arguments are supported.
A value of -1 specifies that the method's last parameter is
a pointer to a
safe array of variants.
Any number of variant arguments
greater than
cParams
-1 must be packaged by the caller into a safe
array and passed
as the final parameter.
The caller must free this array of optional parameters
after control is returned from the call.
Any other number indicates that the last
n
parameters of the function
are variants and do not need to be specified by the caller explicitly.
The
parameters left unspecified should be filled in by the compiler or interpreter
as variants of type
VT_ERROR
with the value
DISP_E_PARAMNOTFOUND
.
For 16-bit systems (Macintosh), the fields
cScodes
and
lprgscode
store the count and the set of errors that a function can return.
If
cScodes
= -1, then the set of errors is unknown.
If
cScodes
= -1,
or if
cScodes = 0, then
lprgscodeis
undefined.
Header file: | WTYPES.H |
typedef void *HANDLE;
typedef HANDLE HBITMAP;
Handle to an enhanced metafile.
typedef HANDLE HENHMETAFILE;
Handle to a global memory block.
typedef HANDLE HGLOBAL;
typedef HANDLE HINSTANCE;
typedef HANDLE HKEY;
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;
A handle that identifies a type description.
typedef unsigned long HREFTYPE;
typedef HANDLE HTASK;
#ifndef HUGEP #if defined(_WIN32) || defined(_MPPC_) #define HUGEP #else #define HUGEP __huge #endif // WIN32 #endif // HUGEP
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.
Interface pointer identifier. It is identical to a GUID.
typedef GUID IPID;
Language identifier.
The first release of Windows NT supports 35 sublanguages/locales. The following 28 sublanguages/locales use 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:
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:
Identifier |
Sublanguage/Locale |
Language Code |
0x0419 | Russian | RUS |
The following sublanguage/locale uses the Other script:
Identifier |
Sublanguage/Locale
|
Language Code
|
0x0408 | Greek | ELL |
The following special identifiers are also defined:
Identifier |
Sublanguage/Locale
|
0x0000 | Language-Neutral |
0x0400 | Process Default Language |
Identifies a locale for national language support. Locale information is used for international string comparisons and localized member names.
typedef unsigned long LCID;
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.
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: |
Value |
Meaning
|
0 | No leading zeros |
1 | Leading zeros |
LOCALE_INEGNUMBER | Negative number mode. The mode can be one of these values: |
Value |
Meaning
|
0 | (1.1) |
1 | -1.1 |
2 | - 1.1 |
3 | 1.1- |
4 | 1.1 - |
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: |
Value |
Meaning
|
0 | Prefix, no separation |
1 | Suffix, no separation |
2 | Prefix, 1-char. separation |
3 | Suffix, 1-char. separation |
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: |
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 $) |
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: |
Value |
Meaning
|
0 | Month-Day-Year |
1 | Day-Month-Year |
2 | Year-Month-Day |
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: |
Value |
Meaning
|
0 | Month-Day-Year |
1 | Day-Month-Year |
2 | Year-Month-Day |
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: |
Value |
Meaning
|
0 | AM / PM 12-hour format |
1 | 24-hour format |
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: |
Value |
Meaning
|
0 | Abbreviated 2-digit century |
1 | Full 4-digit century |
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: |
Value |
Meaning
|
0 | No leading zeros for hours |
1 | Leading zeros for hours |
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: |
Value |
Meaning
|
0 | No leading zeros for days |
1 | Leading zeros for days |
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: |
Value |
Meaning
|
0 | No leading zeros for months |
1 | Leading zeros for months |
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: |
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) |
LOCALE_IOPTIONALCALENDAR |
Additional calendar types. This can be a zero-separated list of one or more of these calendars type 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) |
LOCALE_IFIRSTDAYOFWEEK |
Specifier for the first day in a week. The specifier can be one of these values: |
Value |
Meaning
|
0 | LOCALE_SDAYNAME1 |
1 | LOCALE_SDAYNAME2 |
2 | LOCALE_SDAYNAME3 |
3 | LOCALE_SDAYNAME4 |
4 | LOCALE_SDAYNAME5 |
5 | LOCALE_SDAYNAME6 |
6 | LOCALE_SDAYNAME7 |
LOCALE_IFIRSTWEEKOFYEAR |
Specifier for the first week of the year. The specifier can be one of these 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. |
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: |
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. |
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.
|
typedef long LONG;
typedef [unique] IbindCtx *LPBC;
typedef unsigned char FAR *LPBYTE;
typedef CLSID *LPCLSID;
A pointer to an
OLECHAR
array.
typedef [string] const OLECHAR *LPOLESTR;
Pointer to a constant null-terminated Unicode or Windows character string.
typedef const TCHAR FAR *LPCTSTR;
Pointer to a constant null-terminated Unicode character string.
typedef [string] const WCHAR *LPCWSTR;
typedef DWORD *LPDWORD;
A pointer to an interface identifier.
typedef IID *LPIID;
A pointer to an
IMalloc()
interface.
typedef [unique] IMalloc()
*LPMALLOC;
A pointer to an
IMallocSpy()
interface.
typedef [unique] IMallocSpy()
*LPMALLOCSPY;
A pointer to an
IMarshal()
interface.
typedef [unique] IMarshal()
*LPMARSHAL;
A pointer to an
IMoniker()
interface.
typedef [unique] IMoniker()
*LPMONIKER;
A pointer to an
OLECHAR
array.
typedef [string] OLECHAR *LPOLESTR;
A pointer to the running object table interface.
Typedef [unique] IRunningObjectTable()
*LPRUNNINGOBJECTTABLE;
typedef struct _SECURITY_ATTRIBUTES { DWORD nLength; [size_is(nLength)] LPVOID lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
Pointer to a null-terminated Windows character string.
typedef [string] CHAR *LPSTR;
Pointer to an
IStream()
interface.
typedef [unique] IStream()
*LPSTREAM;
A pointer to an
IUnknown()
interface.
typedef [unique] IUnknown()
*LPUNKNOWN;
typedef void *LPVOID;
typedef WORD *LPWORD;
Pointer to a null-terminated Unicode character string.
typedef [string] WCHAR *LPWSTR;
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.
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.
typedef WCHAR OLECHAR;
typedef struct _FILETIME { DWORD dwLowDateTime; DWORD dwHighDateTime; } FILETIME, *PFILETIME, *LPFILETIME;
typedef HKEY FAR *PHKEY;
A pointer to an unsigned long.
typedef ULONG PROPID;
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
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.
Specifies the value of the property identifier. Use either this value or the following lpwstr, not both.
Specifies the string name of the property as a null-terminated Unicode string.
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()
.
Use version 4.0 or later.
Use Windows 95 or later. Available as a redistributable for Windows 95.
Unsupported.
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.
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
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.
BSTR s
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):
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.
Use version 4.0 or later.
Use Windows 95 or later. Available as a redistributable for Windows 95.
Unsupported.
A pointer to a security descriptor.
typedef PVOID PSECURITY_DESCRIPTOR;
Pointer to an unsigned long (32 bits).
typedef ULONG *PULONG;
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
typedef void *PVOID;
Pointer to a Unicode character.
typedef WCHAR *PWCHAR;
typedef CLSID *REFCLSID;
typedef FMTID *REFFMTID;
A pointer to a globally unique identifier.
typedef GUID *REFGUID;
A pointer to an interface identifier.
typedef IID *REFIID;
Controls how a type library is registered. It is defined as follows:
typedef enum tagREGKIND{ REGKIND_DEFAULT, REGKIND_REGISTER, REGKIND_NONE } REGKIND;
Value |
Description
|
REGKIND_DEFAULT |
Use default register behavior |
REGKIND_REGISTER |
Registered type |
REGKIND_NONE |
Not a registered type |
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.
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.
A pointer to the authorization service.
typedef void __RPC_FAR *RPC_AUTHZ_HANDLE;
#define RPC_FAR
typedef struct tagRPCOLEMESSAGE { void *reserved1; RPCOLEDATAREP dataRepresentation; void *Buffer; ULONG cbBuffer; ULONG iMethod; void *reserved2[5]; ULONG rpcFlags; } RPCOLEMESSAGE;
Header: Declared in
winnt.h
.
The
SECURITY_INFORMATION
structure identifies the
object-related security
information being set or queried.
This security information includes:
The owner of an object
The primary group of an object
The discretionary access-control list (ACL) of an object
typedef DWORD SECURITY_INFORMATION;
Each item of security information is designated by a bit flag. The following values specify the bits:
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. |
Use version 3.1 or later.
Unsupported.
Unsupported.
typedef struct tagSIZEL { LONG cx; LONG cy; } SIZEL, *PSIZEL, *LPSIZEL;
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;
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.
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.
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.
When used in
CoInitializeSecurity()
, set
on return
to indicate the status of the
call to register the authentication services.
Use version 4.0 or later.
Use Windows 95 or later. Available as a redistributable for Windows 95.
Unsupported.
Standard API calling convention.
#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE
Identifies the target operating system platform. It is defined as follows:
typedef enum tagSYSKIND { SYS_WIN16, SYS_WIN32, SYS_MAC } SYSKIND;
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. |
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.
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;
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.
typedef unsigned int UINT;
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;
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.
Use version 3.1 or later.
Use Windows 95 or later.
Use version 1.0 or later.
typedef DWORD ULONG;
typedef unsigned short USHORT;
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
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.
VARIANT
s
can be passed
by value, even if
VARIANTARG
s 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
VARIANTARG
s, 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:
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.
VARIANTARG s 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.
|
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.
#define VOID void
typedef wchar_t WCHAR
Calling convention for the Win32 API.
#define WINAPI FAR PASCAL
Calling convention for the Windows OLE API.
#define WINOLEAPI STDAPI
typedef unsigned short WORD;