diff --git a/dlls/user32/dde_misc.c b/dlls/user32/dde_misc.c index fda8255b18..1a9b662bd5 100644 --- a/dlls/user32/dde_misc.c +++ b/dlls/user32/dde_misc.c @@ -341,7 +341,7 @@ static LRESULT CALLBACK WDML_EventProc(HWND hwndEvent, UINT uMsg, WPARAM wParam, * */ UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback, - DWORD afCmd, DWORD ulRes, BOOL bUnicode, BOOL b16) + DWORD afCmd, DWORD ulRes, BOOL bUnicode) { WDML_INSTANCE* pInstance; WDML_INSTANCE* reference_inst; @@ -377,7 +377,6 @@ UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback, pInstance->threadID = GetCurrentThreadId(); pInstance->callback = *pfnCallback; pInstance->unicode = bUnicode; - pInstance->win16 = b16; pInstance->nodeList = NULL; /* node will be added later */ pInstance->monitorFlags = afCmd & MF_MASK; pInstance->wStatus = 0; @@ -591,7 +590,7 @@ UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback, UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback, DWORD afCmd, DWORD ulRes) { - return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, FALSE, FALSE); + return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, FALSE); } /****************************************************************************** @@ -611,7 +610,7 @@ UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback, UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, DWORD afCmd, DWORD ulRes) { - return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE, FALSE); + return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE); } /***************************************************************** @@ -728,18 +727,10 @@ HDDEDATA WDML_InvokeCallback(WDML_INSTANCE* pInstance, UINT uType, UINT uFmt, H if (pInstance == NULL) return NULL; - TRACE("invoking CB%d[%p] (%x %x %p %p %p %p %lx %lx)\n", - pInstance->win16 ? 16 : 32, pInstance->callback, uType, uFmt, + TRACE("invoking CB[%p] (%x %x %p %p %p %p %lx %lx)\n", + pInstance->callback, uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2); - if (pInstance->win16) - { - ret = WDML_InvokeCallback16(pInstance->callback, uType, uFmt, hConv, - hsz1, hsz2, hdata, dwData1, dwData2); - } - else - { - ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2); - } + ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2); TRACE("done => %p\n", ret); return ret; } diff --git a/dlls/user32/dde_private.h b/dlls/user32/dde_private.h index ed88ce3fc4..c4e4fb41b8 100644 --- a/dlls/user32/dde_private.h +++ b/dlls/user32/dde_private.h @@ -157,7 +157,6 @@ typedef struct tagWDML_INSTANCE BOOL monitor; /* have these two as full Booleans cos they'll be tested frequently */ BOOL clientOnly; /* bit wasteful of space but it will be faster */ BOOL unicode; /* Flag to indicate Win32 API used to initialise */ - BOOL win16; /* flag to indicate Win16 API used to initialize */ HSZNode* nodeList; /* for cleaning upon exit */ PFNCALLBACK callback; DWORD CBFflags; @@ -189,9 +188,6 @@ typedef enum { extern HDDEDATA WDML_InvokeCallback(WDML_INSTANCE* pInst, UINT uType, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA hdata, ULONG_PTR dwData1, ULONG_PTR dwData2) DECLSPEC_HIDDEN; -extern HDDEDATA WDML_InvokeCallback16(PFNCALLBACK pfn, UINT uType, UINT uFmt, HCONV hConv, - HSZ hsz1, HSZ hsz2, HDDEDATA hdata, - DWORD dwData1, DWORD dwData2) DECLSPEC_HIDDEN; extern WDML_SERVER* WDML_AddServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic) DECLSPEC_HIDDEN; extern void WDML_RemoveServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic) DECLSPEC_HIDDEN; extern WDML_SERVER* WDML_FindServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic) DECLSPEC_HIDDEN; @@ -201,7 +197,7 @@ extern WDML_QUEUE_STATE WDML_ServerHandle(WDML_CONV* pConv, WDML_XACT* pXAct) DE HDDEDATA WDML_ClientHandle(WDML_CONV *pConv, WDML_XACT *pXAct, DWORD dwTimeout, LPDWORD pdwResult) DECLSPEC_HIDDEN; /* called both in DdeClientTransaction and server side. */ extern UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback, - DWORD afCmd, DWORD ulRes, BOOL bUnicode, BOOL b16) DECLSPEC_HIDDEN; + DWORD afCmd, DWORD ulRes, BOOL bUnicode) DECLSPEC_HIDDEN; extern WDML_CONV* WDML_AddConv(WDML_INSTANCE* pInstance, WDML_SIDE side, HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer) DECLSPEC_HIDDEN; extern void WDML_RemoveConv(WDML_CONV* pConv, WDML_SIDE side) DECLSPEC_HIDDEN; diff --git a/dlls/user32/ddeml16.c b/dlls/user32/ddeml16.c index 375ee452f8..1bc0f11ad8 100644 --- a/dlls/user32/ddeml16.c +++ b/dlls/user32/ddeml16.c @@ -5,7 +5,7 @@ * Copyright 1997 Len White * Copyright 1999 Keith Matthews * Copyright 2000 Corel - * Copyright 2001,2002 Eric Pouech + * Copyright 2001,2002,2009 Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +22,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" +#include "wine/port.h" + #include #include #include "windef.h" @@ -30,7 +33,6 @@ #include "wownt32.h" #include "dde.h" #include "ddeml.h" -#include "dde_private.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ddeml); @@ -87,15 +89,14 @@ static void map3216_conv_context(CONVCONTEXT16* cc16, const CONVCONTEXT* cc32) cc16->dwSecurity = cc32->dwSecurity; } - /****************************************************************** * WDML_InvokeCallback16 * * */ -HDDEDATA WDML_InvokeCallback16(PFNCALLBACK pfn, UINT uType, UINT uFmt, - HCONV hConv, HSZ hsz1, HSZ hsz2, - HDDEDATA hdata, DWORD dwData1, DWORD dwData2) +static HDDEDATA CALLBACK WDML_InvokeCallback16(DWORD pfn16, UINT uType, UINT uFmt, + HCONV hConv, HSZ hsz1, HSZ hsz2, + HDDEDATA hdata, ULONG_PTR dwData1, ULONG_PTR dwData2) { DWORD d1 = 0; HDDEDATA ret; @@ -133,7 +134,7 @@ HDDEDATA WDML_InvokeCallback16(PFNCALLBACK pfn, UINT uType, UINT uFmt, args[2] = LOWORD(d1); args[1] = HIWORD(dwData2); args[0] = LOWORD(dwData2); - WOWCallback16Ex( (DWORD)pfn, WCB16_PASCAL, sizeof(args), args, (DWORD *)&ret ); + WOWCallback16Ex(pfn16, WCB16_PASCAL, sizeof(args), args, (DWORD *)&ret); switch (uType) { @@ -145,14 +146,89 @@ HDDEDATA WDML_InvokeCallback16(PFNCALLBACK pfn, UINT uType, UINT uFmt, return ret; } +#define MAX_THUNKS 32 +/* As DDEML doesn't provide a way to get back to an InstanceID when + * a callback is run, we use thunk in order to implement simply the + * 32bit->16bit callback mechanism. + * For each 16bit instance, we create a thunk, which will be passed as + * a 32bit callback. This thunk also stores (in the code!) the 16bit + * address of the 16bit callback, and passes it back to + * WDML_InvokeCallback16. + * The code below is mainly to create the thunks themselved + */ +static struct ddeml_thunk +{ + BYTE popl_eax; /* popl %eax (return address) */ + BYTE pushl_func; /* pushl $pfn16 (16bit callback function) */ + SEGPTR pfn16; + BYTE pushl_eax; /* pushl %eax */ + BYTE jmp; /* ljmp WDML_InvokeCallback16 */ + DWORD callback; + DWORD instId; /* instance ID */ +} *DDEML16_Thunks; + +static CRITICAL_SECTION ddeml_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &ddeml_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": ddeml_cs") } +}; +static CRITICAL_SECTION ddeml_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +static struct ddeml_thunk* DDEML_AddThunk(DWORD instId, DWORD pfn16) +{ + struct ddeml_thunk* thunk; + + if (!DDEML16_Thunks) + { + DDEML16_Thunks = VirtualAlloc(NULL, MAX_THUNKS * sizeof(*DDEML16_Thunks), MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (!DDEML16_Thunks) return NULL; + for (thunk = DDEML16_Thunks; thunk < &DDEML16_Thunks[MAX_THUNKS]; thunk++) + { + thunk->popl_eax = 0x58; /* popl %eax */ + thunk->pushl_func = 0x68; /* pushl $pfn16 */ + thunk->pfn16 = 0; + thunk->pushl_eax = 0x50; /* pushl %eax */ + thunk->jmp = 0xe9; /* jmp WDML_InvokeCallback16 */ + thunk->callback = (char *)WDML_InvokeCallback16 - (char *)(&thunk->callback + 1); + thunk->instId = 0; + } + } + for (thunk = DDEML16_Thunks; thunk < &DDEML16_Thunks[MAX_THUNKS]; thunk++) + { + /* either instId is 0, and we're looking for an empty slot, or + * instId is an already existing instance, and we should find its thunk + */ + if (thunk->instId == instId) + { + thunk->pfn16 = pfn16; + return thunk; + } + } + FIXME("Out of ddeml-thunks. Bump MAX_THUNKS\n"); + return NULL; +} + /****************************************************************************** * DdeInitialize (DDEML.2) */ UINT16 WINAPI DdeInitialize16(LPDWORD pidInst, PFNCALLBACK16 pfnCallback, DWORD afCmd, DWORD ulRes) { - return WDML_Initialize(pidInst, (PFNCALLBACK)pfnCallback, afCmd, ulRes, - FALSE, TRUE); + UINT16 ret; + struct ddeml_thunk* thunk; + + EnterCriticalSection(&ddeml_cs); + if ((thunk = DDEML_AddThunk(*pidInst, (DWORD)pfnCallback))) + { + ret = DdeInitializeA(pidInst, (PFNCALLBACK)thunk, afCmd, ulRes); + if (ret == DMLERR_NO_ERROR) thunk->instId = *pidInst; + } + else ret = DMLERR_SYS_ERROR; + LeaveCriticalSection(&ddeml_cs); + return ret; } /***************************************************************** @@ -160,7 +236,23 @@ UINT16 WINAPI DdeInitialize16(LPDWORD pidInst, PFNCALLBACK16 pfnCallback, */ BOOL16 WINAPI DdeUninitialize16(DWORD idInst) { - return (BOOL16)DdeUninitialize(idInst); + struct ddeml_thunk* thunk; + BOOL16 ret = FALSE; + + if (!DdeUninitialize(idInst)) return FALSE; + EnterCriticalSection(&ddeml_cs); + for (thunk = DDEML16_Thunks; thunk < &DDEML16_Thunks[MAX_THUNKS]; thunk++) + { + if (thunk->instId == idInst) + { + thunk->instId = 0; + ret = TRUE; + break; + } + } + LeaveCriticalSection(&ddeml_cs); + if (!ret) FIXME("Should never happen\n"); + return ret; } /*****************************************************************