diff --git a/include/ddeml.h b/include/ddeml.h index 79c12f00a03..73f24543b32 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 @@ HCONV WINAPI DdeQueryNextServer32(HCONVLIST, HCONV); #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 @@ BOOL16 WINAPI DdeEnableCallback16(DWORD,HCONV,UINT16); 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 c0b61975727..c9740a0ea9a 100644 --- a/misc/ddeml.c +++ b/misc/ddeml.c @@ -7,15 +7,142 @@ /* Only empty stubs for now */ +#include +#include #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 @@ BOOL16 WINAPI DdeUninitialize16( DWORD idInst ) */ 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 @@ HCONV WINAPI DdeQueryNextServer32( HCONVLIST hConvList, HCONV hConvPrev ) */ 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 @@ DWORD WINAPI DdeQueryString32A(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, I 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 DdeQueryString32A(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, I */ 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 @@ DWORD WINAPI DdeQueryString32W(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, 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 @@ HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage ) * 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 @@ HSZ WINAPI DdeCreateStringHandle32W( 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 @@ BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz ) * 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 @@ BOOL32 WINAPI DdeFreeDataHandle32( HDDEDATA hData ) } + + /***************************************************************** * DdeKeepStringHandle16 (DDEML.24) */ @@ -617,16 +815,144 @@ UINT32 WINAPI DdeGetLastError32( DWORD idInst ) */ 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 993f5416da9..9a10ec3debd 100644 --- a/relay32/user32.spec +++ b/relay32/user32.spec @@ -92,7 +92,7 @@ init MAIN_UserInit 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 @@ init MAIN_UserInit 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 @@ init MAIN_UserInit 620 stdcall GetTaskmanWindow () GetTaskmanWindow 621 stdcall SetTaskmanWindow (long) SetTaskmanWindow 622 stdcall GetProgmanWindow () GetProgmanWindow +623 stdcall DdeCmpStringHandlesW(long long) DdeCmpStringHandles32W