| /* |
| * DDEML library |
| * |
| * Copyright 1997 Alexandre Julliard |
| * Copyright 1997 Len White |
| * Copyright 1999 Keith Matthews |
| * Copyright 2000 Corel |
| * 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 |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdarg.h> |
| #include <string.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wine/windef16.h" |
| #include "wine/winbase16.h" |
| #include "wownt32.h" |
| #include "dde.h" |
| #include "ddeml.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(ddeml); |
| |
| |
| typedef HDDEDATA (CALLBACK *PFNCALLBACK16)(UINT16,UINT16,HCONV,HSZ,HSZ,HDDEDATA, |
| DWORD,DWORD); |
| |
| typedef struct |
| { |
| UINT16 cb; |
| UINT16 wFlags; |
| UINT16 wCountryID; |
| INT16 iCodePage; |
| DWORD dwLangID; |
| DWORD dwSecurity; |
| } CONVCONTEXT16, *LPCONVCONTEXT16; |
| |
| typedef struct |
| { |
| DWORD cb; |
| DWORD hUser; |
| HCONV hConvPartner; |
| HSZ hszSvcPartner; |
| HSZ hszServiceReq; |
| HSZ hszTopic; |
| HSZ hszItem; |
| UINT16 wFmt; |
| UINT16 wType; |
| UINT16 wStatus; |
| UINT16 wConvst; |
| UINT16 wLastError; |
| HCONVLIST hConvList; |
| CONVCONTEXT16 ConvCtxt; |
| } CONVINFO16, *LPCONVINFO16; |
| |
| static void map1632_conv_context(CONVCONTEXT* cc32, const CONVCONTEXT16* cc16) |
| { |
| cc32->cb = sizeof(*cc32); |
| cc32->wFlags = cc16->wFlags; |
| cc32->wCountryID = cc16->wCountryID; |
| cc32->iCodePage = cc16->iCodePage; |
| cc32->dwLangID = cc16->dwLangID; |
| cc32->dwSecurity = cc16->dwSecurity; |
| } |
| |
| static void map3216_conv_context(CONVCONTEXT16* cc16, const CONVCONTEXT* cc32) |
| { |
| cc16->cb = sizeof(*cc16); |
| cc16->wFlags = cc32->wFlags; |
| cc16->wCountryID = cc32->wCountryID; |
| cc16->iCodePage = cc32->iCodePage; |
| cc16->dwLangID = cc32->dwLangID; |
| cc16->dwSecurity = cc32->dwSecurity; |
| } |
| |
| /****************************************************************** |
| * WDML_InvokeCallback16 |
| * |
| * |
| */ |
| 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; |
| CONVCONTEXT16 cc16; |
| WORD args[16]; |
| |
| switch (uType) |
| { |
| case XTYP_CONNECT: |
| case XTYP_WILDCONNECT: |
| if (dwData1) |
| { |
| map3216_conv_context(&cc16, (const CONVCONTEXT*)dwData1); |
| d1 = MapLS(&cc16); |
| } |
| break; |
| default: |
| d1 = dwData1; |
| break; |
| } |
| args[15] = HIWORD(uType); |
| args[14] = LOWORD(uType); |
| args[13] = HIWORD(uFmt); |
| args[12] = LOWORD(uFmt); |
| args[11] = HIWORD(hConv); |
| args[10] = LOWORD(hConv); |
| args[9] = HIWORD(hsz1); |
| args[8] = LOWORD(hsz1); |
| args[7] = HIWORD(hsz2); |
| args[6] = LOWORD(hsz2); |
| args[5] = HIWORD(hdata); |
| args[4] = LOWORD(hdata); |
| args[3] = HIWORD(d1); |
| args[2] = LOWORD(d1); |
| args[1] = HIWORD(dwData2); |
| args[0] = LOWORD(dwData2); |
| WOWCallback16Ex(pfn16, WCB16_PASCAL, sizeof(args), args, (DWORD *)&ret); |
| |
| switch (uType) |
| { |
| case XTYP_CONNECT: |
| case XTYP_WILDCONNECT: |
| if (d1 != 0) UnMapLS(d1); |
| break; |
| } |
| 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 themselves |
| */ |
| #include "pshpack1.h" |
| 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; |
| #include "poppack.h" |
| |
| 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) |
| { |
| 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; |
| } |
| |
| /***************************************************************** |
| * DdeUninitialize (DDEML.3) |
| */ |
| BOOL16 WINAPI DdeUninitialize16(DWORD 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; |
| } |
| |
| /***************************************************************** |
| * DdeConnectList [DDEML.4] |
| */ |
| |
| HCONVLIST WINAPI DdeConnectList16(DWORD idInst, HSZ hszService, HSZ hszTopic, |
| HCONVLIST hConvList, LPCONVCONTEXT16 pCC16) |
| { |
| CONVCONTEXT cc; |
| CONVCONTEXT* pCC = NULL; |
| |
| if (pCC16) |
| map1632_conv_context(pCC = &cc, pCC16); |
| return DdeConnectList(idInst, hszService, hszTopic, hConvList, pCC); |
| } |
| |
| /***************************************************************** |
| * DdeQueryNextServer [DDEML.5] |
| */ |
| HCONV WINAPI DdeQueryNextServer16(HCONVLIST hConvList, HCONV hConvPrev) |
| { |
| return DdeQueryNextServer(hConvList, hConvPrev); |
| } |
| |
| /***************************************************************** |
| * DdeDisconnectList (DDEML.6) |
| */ |
| BOOL16 WINAPI DdeDisconnectList16(HCONVLIST hConvList) |
| { |
| return (BOOL16)DdeDisconnectList(hConvList); |
| } |
| |
| |
| /***************************************************************** |
| * DdeQueryString (DDEML.23) |
| */ |
| DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, |
| INT16 codepage) |
| { |
| return DdeQueryStringA(idInst, hsz, lpsz, cchMax, codepage); |
| } |
| |
| /***************************************************************** |
| * DdeConnect (DDEML.7) |
| */ |
| HCONV WINAPI DdeConnect16(DWORD idInst, HSZ hszService, HSZ hszTopic, |
| LPCONVCONTEXT16 pCC16) |
| { |
| CONVCONTEXT cc; |
| CONVCONTEXT* pCC = NULL; |
| |
| if (pCC16) |
| map1632_conv_context(pCC = &cc, pCC16); |
| return DdeConnect(idInst, hszService, hszTopic, pCC); |
| } |
| |
| /***************************************************************** |
| * DdeDisconnect (DDEML.8) |
| */ |
| BOOL16 WINAPI DdeDisconnect16(HCONV hConv) |
| { |
| return (BOOL16)DdeDisconnect(hConv); |
| } |
| |
| /***************************************************************** |
| * DdeSetUserHandle (DDEML.10) |
| */ |
| BOOL16 WINAPI DdeSetUserHandle16(HCONV hConv, DWORD id, DWORD hUser) |
| { |
| return DdeSetUserHandle(hConv, id, hUser); |
| } |
| |
| /***************************************************************** |
| * DdeCreateDataHandle (DDEML.14) |
| */ |
| HDDEDATA WINAPI DdeCreateDataHandle16(DWORD idInst, LPBYTE pSrc, DWORD cb, |
| DWORD cbOff, HSZ hszItem, UINT16 wFmt, |
| UINT16 afCmd) |
| { |
| return DdeCreateDataHandle(idInst, pSrc, cb, cbOff, hszItem, wFmt, afCmd); |
| } |
| |
| /***************************************************************** |
| * DdeCreateStringHandle (DDEML.21) |
| */ |
| HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage) |
| { |
| if (codepage) |
| { |
| return DdeCreateStringHandleA(idInst, str, codepage); |
| } |
| else |
| { |
| TRACE("Default codepage supplied\n"); |
| return DdeCreateStringHandleA(idInst, str, CP_WINANSI); |
| } |
| } |
| |
| /***************************************************************** |
| * DdeFreeStringHandle (DDEML.22) |
| */ |
| BOOL16 WINAPI DdeFreeStringHandle16(DWORD idInst, HSZ hsz) |
| { |
| return (BOOL16)DdeFreeStringHandle(idInst, hsz); |
| } |
| |
| /***************************************************************** |
| * DdeFreeDataHandle (DDEML.19) |
| */ |
| BOOL16 WINAPI DdeFreeDataHandle16(HDDEDATA hData) |
| { |
| return (BOOL16)DdeFreeDataHandle(hData); |
| } |
| |
| /***************************************************************** |
| * DdeKeepStringHandle (DDEML.24) |
| */ |
| BOOL16 WINAPI DdeKeepStringHandle16(DWORD idInst, HSZ hsz) |
| { |
| return DdeKeepStringHandle(idInst, hsz); |
| } |
| |
| /***************************************************************** |
| * DdeClientTransaction (DDEML.11) |
| */ |
| HDDEDATA WINAPI DdeClientTransaction16(LPVOID pData, DWORD cbData, HCONV hConv, |
| HSZ hszItem, UINT16 wFmt, UINT16 wType, |
| DWORD dwTimeout, LPDWORD pdwResult) |
| { |
| if (cbData != (DWORD)-1) |
| { |
| /* pData is not a pointer if cbData is -1, so we linearize the address |
| * here rather than in the calling code. */ |
| pData = MapSL((SEGPTR)pData); |
| } |
| return DdeClientTransaction(pData, cbData, hConv, hszItem, |
| wFmt, wType, dwTimeout, pdwResult); |
| } |
| |
| /***************************************************************** |
| * |
| * DdeAbandonTransaction (DDEML.12) |
| * |
| */ |
| BOOL16 WINAPI DdeAbandonTransaction16(DWORD idInst, HCONV hConv, DWORD idTransaction) |
| { |
| return (BOOL16)DdeAbandonTransaction(idInst, hConv, idTransaction); |
| } |
| |
| /***************************************************************** |
| * DdePostAdvise [DDEML.13] |
| */ |
| BOOL16 WINAPI DdePostAdvise16(DWORD idInst, HSZ hszTopic, HSZ hszItem) |
| { |
| return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem); |
| } |
| |
| /***************************************************************** |
| * DdeAddData (DDEML.15) |
| */ |
| HDDEDATA WINAPI DdeAddData16(HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff) |
| { |
| return DdeAddData(hData, pSrc, cb, cbOff); |
| } |
| |
| /***************************************************************** |
| * DdeGetData [DDEML.16] |
| */ |
| DWORD WINAPI DdeGetData16(HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff) |
| { |
| return DdeGetData(hData, pDst, cbMax, cbOff); |
| } |
| |
| /***************************************************************** |
| * DdeAccessData (DDEML.17) |
| */ |
| LPBYTE WINAPI DdeAccessData16(HDDEDATA hData, LPDWORD pcbDataSize) |
| { |
| FIXME("expect trouble\n"); |
| /* FIXME: there's a memory leak here... */ |
| return (LPBYTE)MapLS(DdeAccessData(hData, pcbDataSize)); |
| } |
| |
| /***************************************************************** |
| * DdeUnaccessData (DDEML.18) |
| */ |
| BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData) |
| { |
| return DdeUnaccessData(hData); |
| } |
| |
| /***************************************************************** |
| * DdeEnableCallback (DDEML.26) |
| */ |
| BOOL16 WINAPI DdeEnableCallback16(DWORD idInst, HCONV hConv, UINT16 wCmd) |
| { |
| return DdeEnableCallback(idInst, hConv, wCmd); |
| } |
| |
| /***************************************************************** |
| * DdeNameService (DDEML.27) |
| */ |
| HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT16 afCmd) |
| { |
| return DdeNameService(idInst, hsz1, hsz2, afCmd); |
| } |
| |
| /***************************************************************** |
| * DdeGetLastError (DDEML.20) |
| */ |
| UINT16 WINAPI DdeGetLastError16(DWORD idInst) |
| { |
| return (UINT16)DdeGetLastError(idInst); |
| } |
| |
| /***************************************************************** |
| * DdeCmpStringHandles (DDEML.36) |
| */ |
| INT16 WINAPI DdeCmpStringHandles16(HSZ hsz1, HSZ hsz2) |
| { |
| return DdeCmpStringHandles(hsz1, hsz2); |
| } |
| |
| /****************************************************************** |
| * DdeQueryConvInfo (DDEML.9) |
| * |
| */ |
| UINT16 WINAPI DdeQueryConvInfo16(HCONV hConv, DWORD idTransaction, |
| LPCONVINFO16 lpConvInfo) |
| { |
| CONVINFO ci32; |
| CONVINFO16 ci16; |
| UINT ret; |
| |
| ci32.cb = sizeof(ci32); |
| ci32.ConvCtxt.cb = sizeof(ci32.ConvCtxt); |
| |
| ret = DdeQueryConvInfo(hConv, idTransaction, &ci32); |
| if (ret == 0) return 0; |
| |
| ci16.hUser = ci32.hUser; |
| ci16.hConvPartner = ci32.hConvPartner; |
| ci16.hszSvcPartner = ci32.hszSvcPartner; |
| ci16.hszServiceReq = ci32.hszServiceReq; |
| ci16.hszTopic = ci32.hszTopic; |
| ci16.hszItem = ci32.hszItem; |
| ci16.wFmt = ci32.wFmt; |
| ci16.wType = ci32.wType; |
| ci16.wStatus = ci32.wStatus; |
| ci16.wConvst = ci32.wConvst; |
| ci16.wLastError = ci32.wLastError; |
| ci16.hConvList = ci32.hConvList; |
| |
| map3216_conv_context(&ci16.ConvCtxt, &ci32.ConvCtxt); |
| |
| memcpy(lpConvInfo, &ci16, lpConvInfo->cb); |
| return lpConvInfo->cb; |
| } |