To carry out a DDE task, many DDEML functions require access to strings. For example, a client must specify a service name and a topic name when it calls the DdeConnect function to request a conversation with a server. An application specifies a string by passing a string handle (HSZ) rather than a pointer in a DDEML function. A string handle is a doubleword value, assigned by the system, that identifies a string.
An application can obtain a string handle for a particular string by calling the DdeCreateStringHandle function. This function registers the string with the system and returns a string handle to the application. The application can pass the handle to DDEML functions that must access the string. The following example obtains string handles for the System topic string and the service name string.
HSZ hszServName;
HSZ hszSysTopic;
.
.
.
hszServName = DdeCreateStringHandle(
idInst, /* instance identifier */
"MyServer", /* string to register */
CP_WINANSI); /* Windows ANSI code page */
hszSysTopic = DdeCreateStringHandle(
idInst, /* instance identifier */
SZDDESYS_TOPIC, /* System topic */
CP_WINANSI); /* Windows ANSI code page */
.
.
.
The idInst parameter in the preceding example specifies the instance identifier obtained by the DdeInitialize function.
An application's DDE callback function receives one or more string handles during most DDE transactions. For example, a server receives two string handles during the XTYP_REQUEST transaction: one identifies a string specifying a topic name, and the other identifies a string specifying an item name. An application can obtain the length of the string that corresponds to a string handle and copy the string to an application-defined buffer by calling the DdeQueryString function, as shown in the following example.
DWORD idInst;
DWORD cb;
HSZ hszServ;
PSTR pszServName;
.
.
.
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0,
CP_WINANSI) + 1;
pszServName = (PSTR) LocalAlloc(LPTR, (UINT) cb);
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI);
.
.
.
An instance-specific string handle cannot be mapped from string handle to string and back to string handle. For instance, although DdeQueryString creates a string from a string handle and then DdeCreateStringHandle creates a string handle from that string, the two handles are not the same, as shown in the following example.
DWORD idInst;
DWORD cb;
HSZ hszInst, hszNew;
PSZ pszInst;
.
.
.
DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI);
hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);
/* hszNew != hszInst ! */
.
.
.
To compare the values of two string handles, use the DdeCmpStringHandles function.
A string handle passed to an application's DDE callback function becomes invalid when the callback function returns. An application can save a string handle for use after the callback function returns by using the DdeKeepStringHandle function.
When an application calls DdeCreateStringHandle, the system enters the specified string into a string table and generates a handle that it uses to access the string. The system also maintains a usage count for each string in the string table.
When an application calls DdeCreateStringHandle and specifies a string that already exists in the table, the system increments the usage count rather than adding another occurrence of the string. (An application can also increment the usage count by using DdeKeepStringHandle.) When an application calls the DdeFreeStringHandle function, the system decrements the usage count.
A string is removed from the table when its usage count equals zero. Because more than one application can obtain the handle of a particular string, an application must not free a string handle more times than it has created or retained the handle. Otherwise, the application can cause the string to be removed from the table, denying other applications access to the string.
The DDEML string-management functions are based on the Windows atom manager and are subject to the same size restrictions as are atoms.