Partial implementation for the following DDE APIs:
DdeCmpStringHandles, DdeCreateStringHandle, DdeFreeStringHandle,
DdeQueryString, DdeUninitialize.
diff --git a/include/ddeml.h b/include/ddeml.h
index 79c12f0..73f2454 100644
--- a/include/ddeml.h
+++ b/include/ddeml.h
@@ -10,6 +10,11 @@
#include "wintypes.h"
+/* Codepage Constants
+ */
+#define CP_WINANSI 1004
+#define CP_WINUNICODE 1200
+
#define MSGF_DDEMGR 0x8001
typedef DWORD HCONVLIST;
@@ -61,7 +66,7 @@
#define DdeQueryNextServer WINELIB_NAME(DdeQueryNextServer)
DWORD WINAPI DdeQueryString32A(DWORD, HSZ, LPSTR, DWORD, INT32);
DWORD WINAPI DdeQueryString32W(DWORD, HSZ, LPWSTR, DWORD, INT32);
-#define DdeQueryString WINELIB_NAME(DdeQueryString)
+#define DdeQueryString WINELIB_NAME_AW(DdeQueryString)
BOOL16 WINAPI DdeDisconnectList16(HCONVLIST);
BOOL32 WINAPI DdeDisconnectList32(HCONVLIST);
#define DdeDisConnectList WINELIB_NAME(DdeDisconnectList)
@@ -110,9 +115,9 @@
BOOL32 WINAPI DdeEnableCallback32(DWORD,HCONV,UINT32);
#define DdeEnableCallback WINELIB_NAME(DdeEnableCallback)
int WINAPI DdeCmpStringHandles16(HSZ,HSZ);
-int WINAPI DdeCmpStringHandles32(HSZ,HSZ);
-#define DdeCmpStringHandles WINELIB_NAME(DdeCmpStringHandles)
-
+int WINAPI DdeCmpStringHandles32A(HSZ,HSZ);
+int WINAPI DdeCmpStringHandles32W(HSZ,HSZ);
+#define DdeCmpStringHandles WINELIB_NAME_AW(DdeCmpStringHandles)
HDDEDATA WINAPI DdeNameService16(DWORD,HSZ,HSZ,UINT16);
HDDEDATA WINAPI DdeNameService32(DWORD,HSZ,HSZ,UINT32);
diff --git a/misc/ddeml.c b/misc/ddeml.c
index c0b6197..c9740a0 100644
--- a/misc/ddeml.c
+++ b/misc/ddeml.c
@@ -7,15 +7,142 @@
/* Only empty stubs for now */
+#include <stdlib.h>
+#include <strings.h>
#include "ddeml.h"
#include "debug.h"
#include "windows.h"
+#include "heap.h"
/* FIXME: What are these values? */
#define DMLERR_NO_ERROR 0
+/* Has defined in atom.c file.
+ */
+#define MAX_ATOM_LEN 255
+
+/* Maximum buffer size ( including the '\0' ).
+ */
+#define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1)
+
static LONG DDE_current_handle;
+/* This is a simple list to keep track of the strings created
+ * by DdeCreateStringHandle. The list is used to free
+ * the strings whenever DdeUninitialize is called.
+ * This mechanism is not complete and does not handle multiple instances.
+ * Most of the DDE API use a DWORD parameter indicating witch instance
+ * of a given program is calling them. The API are supposed to
+ * associate the data to the instance that created it.
+ */
+typedef struct tagHSZNode HSZNode;
+struct tagHSZNode
+{
+ HSZNode* next;
+ HSZ hsz;
+};
+
+/* Start off the list pointer with a NULL.
+ */
+static HSZNode* pHSZNodes = NULL;
+
+
+/******************************************************************************
+ * RemoveHSZNodes (INTERNAL)
+ *
+ * Remove a node from the list of HSZ nodes.
+ */
+static void RemoveHSZNode( DWORD idInst, HSZ hsz )
+{
+ HSZNode* pPrev = NULL;
+ HSZNode* pCurrent = NULL;
+
+ /* Set the current node at the start of the list.
+ */
+ pCurrent = pHSZNodes;
+ /* While we have more nodes.
+ */
+ while( pCurrent != NULL )
+ {
+ /* If we found the node we were looking for.
+ */
+ if( pCurrent->hsz == hsz )
+ {
+ /* Remove the node.
+ */
+ /* If the first node in the list is to to be removed.
+ * Set the global list pointer to the next node.
+ */
+ if( pCurrent == pHSZNodes )
+ {
+ pHSZNodes = pCurrent->next;
+ }
+ /* Just fix the pointers has to skip the current
+ * node so we can delete it.
+ */
+ else
+ {
+ pPrev->next = pCurrent->next;
+ }
+ /* Destroy this node.
+ */
+ free( pCurrent );
+ break;
+ }
+ /* Save the previous node pointer.
+ */
+ pPrev = pCurrent;
+ /* Move on to the next node.
+ */
+ pCurrent = pCurrent->next;
+ }
+}
+
+/******************************************************************************
+ * FreeAndRemoveHSZNodes (INTERNAL)
+ *
+ * Frees up all the strings still allocated in the list and
+ * remove all the nodes from the list of HSZ nodes.
+ */
+static void FreeAndRemoveHSZNodes( DWORD idInst )
+{
+ /* Free any strings created in this instance.
+ */
+ while( pHSZNodes != NULL )
+ {
+ DdeFreeStringHandle32( idInst, pHSZNodes->hsz );
+ }
+}
+
+/******************************************************************************
+ * InsertHSZNode (INTERNAL)
+ *
+ * Insert a node to the head of the list.
+ */
+static void InsertHSZNode( DWORD idInst, HSZ hsz )
+{
+ if( hsz != 0 )
+ {
+ HSZNode* pNew = NULL;
+ /* Create a new node for this HSZ.
+ */
+ pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
+ if( pNew != NULL )
+ {
+ /* Set the handle value.
+ */
+ pNew->hsz = hsz;
+ /* Attach the node to the head of the list.
+ */
+ pNew->next = pHSZNodes;
+ /* The new node is now at the head of the list
+ * so set the global list pointer to it.
+ */
+ pHSZNodes = pNew;
+ }
+ }
+}
+
/******************************************************************************
* DdeInitialize16 (DDEML.2)
@@ -88,7 +215,14 @@
*/
BOOL32 WINAPI DdeUninitialize32( DWORD idInst )
{
+
FIXME(ddeml, "(%ld): stub\n", idInst);
+
+ /* Free the nodes that were not freed by this instance
+ * and remove the nodes from the list of HSZ nodes.
+ */
+ FreeAndRemoveHSZNodes( idInst );
+
return TRUE;
}
@@ -150,6 +284,9 @@
*/
DWORD WINAPI DdeQueryString32A(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT32 iCodePage)
{
+ DWORD ret = 0;
+ CHAR pString[MAX_BUFFER_LEN];
+
FIXME(ddeml,
"(%ld, 0x%lx, %p, %ld, %d): stub\n",
idInst,
@@ -158,7 +295,21 @@
cchMax,
iCodePage);
- return 0;
+ if( iCodePage == CP_WINANSI )
+ {
+ /* If psz is null, we have to return only the length
+ * of the string.
+ */
+ if( psz == NULL )
+ {
+ psz = pString;
+ cchMax = MAX_BUFFER_LEN;
+}
+
+ ret = GlobalGetAtomName32A( hsz, (LPSTR)psz, cchMax );
+ }
+
+ return ret;
}
/*****************************************************************
@@ -166,6 +317,10 @@
*/
DWORD WINAPI DdeQueryString32W(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT32 iCodePage)
{
+ DWORD ret = 0;
+ WCHAR pString[MAX_BUFFER_LEN];
+ int factor = 1;
+
FIXME(ddeml,
"(%ld, 0x%lx, %p, %ld, %d): stub\n",
idInst,
@@ -174,7 +329,23 @@
cchMax,
iCodePage);
- return 0;
+ if( iCodePage == CP_WINUNICODE )
+ {
+ /* If psz is null, we have to return only the length
+ * of the string.
+ */
+ if( psz == NULL )
+ {
+ psz = pString;
+ cchMax = MAX_BUFFER_LEN;
+ /* Note: According to documentation if the psz parameter
+ * was NULL this API must return the length of the string in bytes.
+ */
+ factor = (int) sizeof(WCHAR)/sizeof(BYTE);
+ }
+ ret = GlobalGetAtomName32W( hsz, (LPWSTR)psz, cchMax ) * factor;
+ }
+ return ret;
}
@@ -315,11 +486,19 @@
* Failure: 0
*/
HSZ WINAPI DdeCreateStringHandle32A( DWORD idInst, LPCSTR psz, INT32 codepage )
-{ TRACE(ddeml, "(%ld,%s,%d): stub\n",idInst,debugstr_a(psz),codepage);
+{
+ HSZ hsz = 0;
+ TRACE(ddeml, "(%ld,%s,%d): stub\n",idInst,debugstr_a(psz),codepage);
- if (codepage==1004) /*fixme: should be CP_WINANSI*/
- return GlobalAddAtom32A (psz);
- else
+ if (codepage==CP_WINANSI)
+ {
+ hsz = GlobalAddAtom32A (psz);
+ /* Save the handle so we know to clean it when
+ * uninitialize is called.
+ */
+ InsertHSZNode( idInst, hsz );
+ return hsz;
+ }
return 0;
}
@@ -336,9 +515,20 @@
LPCWSTR psz, /* [in] Pointer to string */
INT32 codepage) /* [in] Code page identifier */
{
+ HSZ hsz = 0;
+
FIXME(ddeml, "(%ld,%s,%d): stub\n",idInst,debugstr_w(psz),codepage);
- DDE_current_handle++;
- return DDE_current_handle;
+
+ if (codepage==CP_WINUNICODE)
+ {
+ hsz = GlobalAddAtom32W (psz);
+ /* Save the handle so we know to clean it when
+ * uninitialize is called.
+ */
+ InsertHSZNode( idInst, hsz );
+ return hsz;
+}
+ return 0;
}
@@ -357,8 +547,14 @@
* fail: zero
*/
BOOL32 WINAPI DdeFreeStringHandle32( DWORD idInst, HSZ hsz )
-{ TRACE( ddeml, "(%ld,%ld): stub\n",idInst, hsz );
- return GlobalDeleteAtom (hsz) ? hsz : 0;
+{
+ TRACE( ddeml, "(%ld,%ld): stub\n",idInst, hsz );
+ /* Remove the node associated with this HSZ.
+ */
+ RemoveHSZNode( idInst, hsz );
+ /* Free the string associated with this HSZ.
+ */
+ return GlobalDeleteAtom (hsz) ? 0 : hsz;
}
@@ -381,6 +577,8 @@
}
+
+
/*****************************************************************
* DdeKeepStringHandle16 (DDEML.24)
*/
@@ -617,16 +815,144 @@
*/
int WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
{
- return DdeCmpStringHandles32(hsz1, hsz2);
+ return DdeCmpStringHandles32A(hsz1, hsz2);
}
/*****************************************************************
- * DdeCmpStringHandles32 (USER32.91)
+ * DdeCmpStringHandles32A (USER32.91)
+ *
+ * Compares the value of two string handles. This comparison is
+ * not case sensitive.
+ *
+ * Returns:
+ * -1 The value of hsz1 is zero or less than hsz2
+ * 0 The values of hsz 1 and 2 are the same or both zero.
+ * 1 The value of hsz2 is zero of less than hsz1
*/
-int WINAPI DdeCmpStringHandles32( HSZ hsz1, HSZ hsz2 )
+int WINAPI DdeCmpStringHandles32A( HSZ hsz1, HSZ hsz2 )
{
- FIXME( ddeml, "(0x%lx, 0x%lx): stub\n", hsz1, hsz2 );
- return 0;
+ CHAR psz1[MAX_BUFFER_LEN];
+ CHAR psz2[MAX_BUFFER_LEN];
+ int ret = 0;
+ int ret1, ret2;
+
+ TRACE( ddeml, "handle 1, handle 2\n" );
+
+ ret1 = GlobalGetAtomName32A( hsz1, psz1, MAX_BUFFER_LEN );
+ ret2 = GlobalGetAtomName32A( hsz2, psz2, MAX_BUFFER_LEN );
+ /* Make sure we found both strings.
+ */
+ if( ret1 == 0 && ret2 == 0 )
+ {
+ /* If both are not found, return both "zero strings".
+ */
+ ret = 0;
+ }
+ else if( ret1 == 0 )
+ {
+ /* If hsz1 is a not found, return hsz1 is "zero string".
+ */
+ ret = -1;
+ }
+ else if( ret2 == 0 )
+ {
+ /* If hsz2 is a not found, return hsz2 is "zero string".
+ */
+ ret = 1;
+ }
+ else
+ {
+ /* Compare the two strings we got ( case insensitive ).
+ */
+ ret = strcasecmp( psz1, psz2 );
+ /* Since strcmp returns any number smaller than
+ * 0 when the first string is found to be less than
+ * the second one we must make sure we are returning
+ * the proper values.
+ */
+ if( ret < 0 )
+ {
+ ret = -1;
+ }
+ else if( ret > 0 )
+ {
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
+
+/*****************************************************************
+ * DdeCmpStringHandles32W (USER32.623)
+ *
+ * Compares the value of two string handles. This comparison is
+ * not case sensitive.
+ *
+ * Returns:
+ * -1 The value of hsz1 is zero or less than hsz2
+ * 0 The values of hsz 1 and 2 are the same or both zero.
+ * 1 The value of hsz2 is zero of less than hsz1
+ */
+int WINAPI DdeCmpStringHandles32W( HSZ hsz1, HSZ hsz2 )
+{
+ WCHAR pwsz1[MAX_BUFFER_LEN];
+ WCHAR pwsz2[MAX_BUFFER_LEN];
+ int ret = 0;
+ int ret1, ret2;
+
+ TRACE( ddeml, "handle 1, handle 2\n" );
+
+ ret1 = GlobalGetAtomName32W( hsz1, pwsz1, MAX_BUFFER_LEN );
+ ret2 = GlobalGetAtomName32W( hsz2, pwsz2, MAX_BUFFER_LEN );
+ /* Make sure we found both strings.
+ */
+ if( ret1 == 0 && ret2 == 0 )
+ {
+ /* If both are not found, return both "zero strings".
+ */
+ ret = 0;
+ }
+ else if( ret1 == 0 )
+ {
+ /* If hsz1 is a not found, return hsz1 is "zero string".
+ */
+ ret = -1;
+ }
+ else if( ret2 == 0 )
+ {
+ /* If hsz2 is a not found, return hsz2 is "zero string".
+ */
+ ret = 1;
+ }
+ else
+ {
+ LPSTR psz1, psz2;
+ psz1 = HEAP_strdupWtoA( GetProcessHeap(), 0, pwsz1 );
+ psz2 = HEAP_strdupWtoA( GetProcessHeap(), 0, pwsz2 );
+ if( psz1 != NULL && psz2 != NULL )
+ {
+ /* Compare the two strings we got ( case insensitive ).
+ */
+ ret = strcasecmp( psz1, psz2 );
+ /* Since strcmp returns any number smaller than
+ * 0 when the first string is found to be less than
+ * the second one we must make sure we are returning
+ * the proper values.
+ */
+ if( ret < 0 )
+ {
+ ret = -1;
+ }
+ else if( ret > 0 )
+ {
+ ret = 1;
+ }
+ }
+ HeapFree( GetProcessHeap(), 0, psz1 );
+ HeapFree( GetProcessHeap(), 0, psz2 );
+ }
+ return ret;
}
diff --git a/relay32/user32.spec b/relay32/user32.spec
index 993f541..9a10ec3 100644
--- a/relay32/user32.spec
+++ b/relay32/user32.spec
@@ -92,7 +92,7 @@
88 stdcall DdeAccessData(long ptr) DdeAccessData32
89 stub DdeAddData
90 stdcall DdeClientTransaction(ptr long long long long long long ptr) DdeClientTransaction32
- 91 stdcall DdeCmpStringHandles(long long) DdeCmpStringHandles32
+ 91 stdcall DdeCmpStringHandlesA(long long) DdeCmpStringHandles32A
92 stdcall DdeConnect(long long long ptr) DdeConnect32
93 stdcall DdeConnectList(long long long long ptr) DdeConnectList32
94 stdcall DdeCreateDataHandle(long ptr long long long long long) DdeCreateDataHandle32
@@ -615,7 +615,6 @@
610 stdcall MonitorFromRect(ptr long) MonitorFromRect
611 stdcall MonitorFromPoint(long long long) MonitorFromPoint
612 stdcall EnumDisplayMonitors(long ptr ptr long) EnumDisplayMonitors
-
613 stdcall PrivateExtractIconExA (long long long long long) PrivateExtractIconExA
614 stdcall PrivateExtractIconExW (long long long long long) PrivateExtractIconExW
615 stdcall PrivateExtractIconsW (long long long long long long long long) PrivateExtractIconsW
@@ -626,3 +625,4 @@
620 stdcall GetTaskmanWindow () GetTaskmanWindow
621 stdcall SetTaskmanWindow (long) SetTaskmanWindow
622 stdcall GetProgmanWindow () GetProgmanWindow
+623 stdcall DdeCmpStringHandlesW(long long) DdeCmpStringHandles32W