Many DDEML functions require access to strings in order to carry out a DDE task. 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 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 need to 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); /* code page */
hszSysTopic = DdeCreateStringHandle(
idInst, /* instance identifier */
SZDDESYS_TOPIC, /* System topic */
CP_WINANSI); /* 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; 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 the following example demonstrates:
DWORD idInst;
DWORD cb;
HSZ hszServ;
PSTR pszServName;
cb = DdeQueryString(idInst, hszServ, (LPSTR) NULL, 0L, CP_WINANSI) + 1;
pszServName = (PSTR) LocalAlloc(LPTR, (WORD) cb);
DdeQueryString(idInst, hszServ, pszServName, cb, CP_WINANSI);
An instance-specific string handle is not mappable from string handle to string to string handle again. For instance, in the following example, the DdeQueryString function creates a string from a string handle and then DdeCreateStringHandle creates a string handle from that string, but the two handles are not the same:
DWORD cb;
HSZ hszInst, hszNew;
PSZ pszInst;
DdeQueryString(idInst, hszInst, pszInst, cb, CP_WINANSI);
hszNew = DdeCreateStringHandle(idInst, pszInst, CP_WINANSI);
/* hszNew != hszInst ! */
A string handle that is 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 systemwide 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 the DdeCreateStringHandle function 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 the DdeKeepStringHandle function.) 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 should not free a string handle more times than it has created or kept the handle. Otherwise, the application could 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 atoms.