Commit 78a4134e authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

- implemented correctly the HSZ as local atoms and added the needed

conversions to global atoms - enhanced internal handle <=> pointer conversions, as well as validity of such objects (life time, destruction, mutual access...) - fixed a few ANSI/Unicode issues, stores most of the data as Unicode - started having both Ansi/Unicode DDE window procs for message A/W transformation - fixed a few segmented pointer issues (mainly in DdeInitialize & DdeGetData) - added most of the CBF_ flags handling - implemented the conversation announcement (XTYP_CONNECT_CONFIRM) on server side - enhanced DdeQueryConfig and implemented DdeReconnect - implemented conversation termination (including XTYP_UNREGISTER) - several others code clean up - added transaction support on server side too
parent 7b3495ac
......@@ -37,7 +37,9 @@ RC_SRCS16 = \
resources/mouse.rc \
resources/version16.rc
GLUE = thunk.c
GLUE = \
dde/ddeml16.c \
thunk.c
EXTRA_OBJS = \
$(TOPOBJDIR)/controls/controls.o \
......
......@@ -16,6 +16,7 @@
#include "wingdi.h"
#include "winuser.h"
#include "winerror.h"
#include "winnls.h"
#include "dde.h"
#include "ddeml.h"
#include "debugtools.h"
......@@ -24,7 +25,8 @@
DEFAULT_DEBUG_CHANNEL(ddeml);
static LRESULT CALLBACK WDML_ClientProc(HWND, UINT, WPARAM, LPARAM); /* only for one client, not conv list */
static const char szClientClassA[] = "DdeClientAnsi";
const char WDML_szClientConvClassA[] = "DdeClientAnsi";
const WCHAR WDML_szClientConvClassW[] = {'D','d','e','C','l','i','e','n','t','U','n','i','c','o','d','e',0};
/******************************************************************************
* DdeConnectList [USER32.@] Establishes conversation with DDE servers
......@@ -44,7 +46,7 @@ HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
HCONVLIST hConvList, LPCONVCONTEXT pCC)
{
FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
hConvList,pCC);
hConvList, pCC);
return (HCONVLIST)1;
}
......@@ -53,19 +55,22 @@ HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
*/
HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev)
{
FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
FIXME("(%d,%d): stub\n", hConvList, hConvPrev);
return 0;
}
/******************************************************************************
* DdeDisconnectList [USER32.@] Destroys list and terminates conversations
*
*
* PARAMS
* hConvList [I] Handle to conversation list
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI DdeDisconnectList(
HCONVLIST hConvList) /* [in] Handle to conversation list */
BOOL WINAPI DdeDisconnectList(HCONVLIST hConvList)
{
FIXME("(%d): stub\n", hConvList);
return TRUE;
......@@ -79,103 +84,133 @@ HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
{
HWND hwndClient;
LPARAM lParam = 0;
UINT uiLow, uiHi;
WNDCLASSEXA wndclass;
WDML_INSTANCE* thisInstance;
WDML_CONV* pConv;
TRACE("(0x%lx,%d,%d,%p)\n",idInst,hszService,hszTopic,pCC);
WDML_INSTANCE* pInstance;
WDML_CONV* pConv = NULL;
ATOM aSrv = 0, aTpc = 0;
thisInstance = WDML_FindInstance(idInst);
if (!thisInstance)
TRACE("(0x%lx,0x%x,0x%x,%p)\n", idInst, hszService, hszTopic, pCC);
EnterCriticalSection(&WDML_CritSect);
pInstance = WDML_GetInstance(idInst);
if (!pInstance)
{
return 0;
goto theEnd;
}
/* make sure this conv is never created */
pConv = WDML_FindConv(thisInstance, WDML_CLIENT_SIDE, hszService, hszTopic);
pConv = WDML_FindConv(pInstance, WDML_CLIENT_SIDE, hszService, hszTopic);
if (pConv != NULL)
{
ERR("This Conv already exists: (0x%lx)\n", (DWORD)pConv);
return (HCONV)pConv;
goto theEnd;
}
/* we need to establish a conversation with
server, so create a window for it */
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_ClientProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szClientClassA;
wndclass.hIconSm = 0;
RegisterClassExA(&wndclass);
if (pInstance->unicode)
{
WNDCLASSEXW wndclass;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_ClientProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WDML_szClientConvClassW;
wndclass.hIconSm = 0;
RegisterClassExW(&wndclass);
hwndClient = CreateWindowA(szClientClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
hwndClient = CreateWindowW(WDML_szClientConvClassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
}
else
{
WNDCLASSEXA wndclass;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_ClientProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WDML_szClientConvClassA;
wndclass.hIconSm = 0;
RegisterClassExA(&wndclass);
SetWindowLongA(hwndClient, 0, (DWORD)thisInstance);
hwndClient = CreateWindowA(WDML_szClientConvClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0);
}
SetWindowLongA(hwndClient, GWL_WDML_INSTANCE, (DWORD)pInstance);
SendMessageA(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient,
PackDDElParam(WM_DDE_INITIATE, (UINT)hszService, (UINT)hszTopic));
if (hszService)
{
aSrv = WDML_MakeAtomFromHsz(hszService);
if (!aSrv) goto theEnd;
}
if (hszTopic)
{
aTpc = WDML_MakeAtomFromHsz(hszTopic);
if (!aTpc) goto theEnd;
}
LeaveCriticalSection(&WDML_CritSect);
lParam = PackDDElParam(WM_DDE_INITIATE, aSrv, aTpc);
SendMessageA(HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, lParam);
FreeDDElParam(WM_DDE_INITIATE, lParam);
if (UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLow, &uiHi))
FreeDDElParam(WM_DDE_INITIATE, lParam);
EnterCriticalSection(&WDML_CritSect);
pInstance = WDML_GetInstance(idInst);
if (!pInstance)
{
goto theEnd;
}
TRACE("WM_DDE_INITIATE was processed\n");
/* At this point, Client WM_DDE_ACK should have saved hwndServer
for this instance id and hwndClient if server responds.
So get HCONV and return it. And add it to conv list */
pConv = (WDML_CONV*)GetWindowLongA(hwndClient, 4);
pConv = WDML_GetConvFromWnd(hwndClient);
if (pConv == NULL || pConv->hwndServer == 0)
{
ERR(".. but no Server window available\n");
return 0;
pConv = NULL;
goto theEnd;
}
pConv->wConvst = XST_CONNECTED;
/* finish init of pConv */
if (pCC != NULL)
{
pConv->convContext = *pCC;
}
return (HCONV)pConv;
}
/*****************************************************************
* DdeDisconnect (USER32.@)
*/
BOOL WINAPI DdeDisconnect(HCONV hConv)
{
WDML_CONV* pConv = NULL;
TRACE("(%ld)\n", (DWORD)hConv);
if (hConv == 0)
{
ERR("DdeDisconnect(): hConv = 0\n");
return 0;
}
pConv = WDML_GetConv(hConv);
if (pConv == NULL)
{
return FALSE;
}
if (!PostMessageA(pConv->hwndServer, WM_DDE_TERMINATE,
(WPARAM)pConv->hwndClient, (LPARAM)hConv))
else
{
ERR("DdeDisconnect(): PostMessage returned 0\n");
return 0;
memset(&pConv->convContext, 0, sizeof(pConv->convContext));
pConv->convContext.cb = sizeof(pConv->convContext);
pConv->convContext.iCodePage = (pInstance->unicode) ? CP_WINUNICODE : CP_WINANSI;
}
return TRUE;
}
theEnd:
LeaveCriticalSection(&WDML_CritSect);
if (aSrv) GlobalDeleteAtom(aSrv);
if (aTpc) GlobalDeleteAtom(aTpc);
return (HCONV)pConv;
}
/*****************************************************************
* DdeReconnect (DDEML.37)
......@@ -183,52 +218,116 @@ BOOL WINAPI DdeDisconnect(HCONV hConv)
*/
HCONV WINAPI DdeReconnect(HCONV hConv)
{
FIXME("empty stub\n");
return 0;
}
WDML_CONV* pConv;
WDML_CONV* pNewConv = NULL;
ATOM aSrv = 0, aTpc = 0;
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv != NULL && (pConv->wStatus & ST_CLIENT))
{
LPARAM lParam;
BOOL ret;
/* to reestablist a connection, we have to make sure that:
* 1/ pConv is the converstation attached to the client window (it wouldn't be
* if a call to DdeReconnect would have already been done...)
* FIXME: is this really an error ???
* 2/ the pConv conversation had really been deconnected
*/
if (pConv == WDML_GetConvFromWnd(pConv->hwndClient) &&
(pConv->wStatus & ST_TERMINATED) && !(pConv->wStatus & ST_CONNECTED))
{
HWND hwndClient = pConv->hwndClient;
HWND hwndServer = pConv->hwndServer;
ATOM aSrv, aTpc;
SetWindowLongA(pConv->hwndClient, GWL_WDML_CONVERSATION, 0);
aSrv = WDML_MakeAtomFromHsz(pConv->hszService);
aTpc = WDML_MakeAtomFromHsz(pConv->hszTopic);
if (!aSrv || !aTpc) goto theEnd;
LeaveCriticalSection(&WDML_CritSect);
lParam = PackDDElParam(WM_DDE_INITIATE, aSrv, aTpc);
ret = SendMessageA(hwndServer, WM_DDE_INITIATE, (WPARAM)hwndClient, lParam);
FreeDDElParam(WM_DDE_INITIATE, lParam);
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv == NULL)
{
FIXME("Should fail reconnection\n");
goto theEnd;
}
if (ret && (pNewConv = WDML_GetConvFromWnd(pConv->hwndClient)) != NULL)
{
/* re-establish all links... */
WDML_LINK* pLink;
for (pLink = pConv->instance->links[WDML_CLIENT_SIDE]; pLink; pLink = pLink->next)
{
if (pLink->hConv == hConv)
{
/* try to reestablish the links... */
DdeClientTransaction(NULL, 0, (HCONV)pNewConv, pLink->hszItem, pLink->uFmt,
pLink->transactionType, 1000, NULL);
}
}
}
else
{
/* reset the conversation as it was */
SetWindowLongA(pConv->hwndClient, GWL_WDML_CONVERSATION, (DWORD)pConv);
}
}
}
typedef enum {
WDML_QS_ERROR, WDML_QS_HANDLED, WDML_QS_PASS
} WDML_QUEUE_STATE;
theEnd:
LeaveCriticalSection(&WDML_CritSect);
if (aSrv) GlobalDeleteAtom(aSrv);
if (aTpc) GlobalDeleteAtom(aTpc);
return (HCONV)pNewConv;
}
/******************************************************************
* WDML_QueueAdvise
* WDML_ClientQueueAdvise
*
* Creates and queue an WM_DDE_ADVISE transaction
*/
static WDML_XACT* WDML_QueueAdvise(WDML_CONV* pConv, UINT wType, UINT wFmt, HSZ hszItem)
static WDML_XACT* WDML_ClientQueueAdvise(WDML_CONV* pConv, UINT wType, UINT wFmt, HSZ hszItem)
{
DDEADVISE* pDdeAdvise;
WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_ADVSTART (with%s data) transaction\n", (wType & XTYPF_NODATA) ? "out" : "");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_ADVISE);
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) return NULL;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE, wFmt, hszItem);
if (!pXAct)
{
GlobalDeleteAtom(atom);
return NULL;
}
pXAct->u.advise.wType = wType & ~0x0F;
pXAct->u.advise.wFmt = wFmt;
pXAct->u.advise.hszItem = hszItem;
pXAct->u.advise.hDdeAdvise = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
pXAct->wType = wType & ~0x0F;
pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
/* pack DdeAdvise */
pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->u.advise.hDdeAdvise);
pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->hMem);
pDdeAdvise->fAckReq = (wType & XTYPF_ACKREQ) ? TRUE : FALSE;
pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) ? TRUE : FALSE;
pDdeAdvise->cfFormat = wFmt;
GlobalUnlock(pXAct->u.advise.hDdeAdvise);
GlobalUnlock(pXAct->hMem);
WDML_QueueTransaction(pConv, pXAct);
if (!PostMessageA(pConv->hwndServer, WM_DDE_ADVISE, (WPARAM)pConv->hwndClient,
PackDDElParam(WM_DDE_ADVISE, (UINT)pXAct->u.advise.hDdeAdvise, (UINT)hszItem)))
{
GlobalFree(pXAct->u.advise.hDdeAdvise);
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pXAct);
return NULL;
}
pXAct->lParam = PackDDElParam(WM_DDE_ADVISE, (UINT)pXAct->hMem, atom);
return pXAct;
}
......@@ -242,82 +341,78 @@ static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_
{
DDEACK ddeAck;
UINT uiLo, uiHi;
WORD wStatus;
HSZ hsz;
if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
{
return WDML_QS_PASS;
}
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
if (DdeCmpStringHandles(uiHi, pXAct->u.advise.hszItem) != 0)
if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
return WDML_QS_PASS;
GlobalDeleteAtom(uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam);
wStatus = uiLo;
ddeAck = *((DDEACK*)&wStatus);
WDML_ExtractAck(uiLo, &ddeAck);
if (ddeAck.fAck)
{
WDML_LINK* pLink;
/* billx: first to see if the link is already created. */
pLink = WDML_FindLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->u.advise.hszItem, pXAct->u.advise.wFmt);
pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->hszItem, pXAct->wFmt);
if (pLink != NULL)
{
/* we found a link, and only need to modify it in case it changes */
pLink->transactionType = pXAct->u.advise.wType;
pLink->transactionType = pXAct->wType;
}
else
{
TRACE("Adding Link with hConv = 0x%lx\n", (DWORD)pConv);
WDML_AddLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->u.advise.wType, pXAct->u.advise.hszItem,
pXAct->u.advise.wFmt);
WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->wType, pXAct->hszItem, pXAct->wFmt);
}
}
else
{
TRACE("Returning TRUE on XTYP_ADVSTART - fAck was FALSE\n");
GlobalFree(pXAct->u.advise.hDdeAdvise);
GlobalFree(pXAct->hMem);
}
pXAct->hDdeData = (HDDEDATA)1;
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_QueueUnadvise
* WDML_ClientQueueUnadvise
*
* queues an unadvise transaction
*/
static WDML_XACT* WDML_QueueUnadvise(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
static WDML_XACT* WDML_ClientQueueUnadvise(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
{
WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_ADVSTOP transaction\n");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_UNADVISE);
if (!pXAct)
return NULL;
pXAct->u.unadvise.wFmt = wFmt;
pXAct->u.unadvise.hszItem = hszItem;
WDML_QueueTransaction(pConv, pXAct);
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) return NULL;
/* end advise loop: post WM_DDE_UNADVISE to server to terminate link
on the specified item. */
if (!PostMessageA(pConv->hwndServer, WM_DDE_UNADVISE, (WPARAM)pConv->hwndClient,
PackDDElParam(WM_DDE_UNADVISE, wFmt, (UINT)hszItem)))
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE, wFmt, hszItem);
if (!pXAct)
{
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pXAct);
GlobalDeleteAtom(atom);
return NULL;
}
/* end advise loop: post WM_DDE_UNADVISE to server to terminate link
* on the specified item.
*/
pXAct->lParam = PackDDElParam(WM_DDE_UNADVISE, wFmt, atom);
return pXAct;
}
......@@ -330,7 +425,7 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM
{
DDEACK ddeAck;
UINT uiLo, uiHi;
WORD wStatus;
HSZ hsz;
if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
{
......@@ -338,14 +433,15 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM
}
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
if (DdeCmpStringHandles(uiHi, pXAct->u.unadvise.hszItem) != 0)
if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
return WDML_QS_PASS;
FreeDDElParam(WM_DDE_ACK, msg->lParam);
GlobalDeleteAtom(uiHi);
wStatus = uiLo;
ddeAck = *((DDEACK*)&wStatus);
WDML_ExtractAck(uiLo, &ddeAck);
TRACE("WM_DDE_ACK received while waiting for a timeout\n");
......@@ -356,43 +452,37 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM
else
{
/* billx: remove the link */
WDML_RemoveLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->u.unadvise.hszItem, pXAct->u.unadvise.wFmt);
WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->hszItem, pXAct->wFmt);
}
pXAct->hDdeData = (HDDEDATA)1;
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_QueueRequest
* WDML_ClientQueueRequest
*
*
*/
static WDML_XACT* WDML_QueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
static WDML_XACT* WDML_ClientQueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
{
WDML_XACT* pXAct;
TRACE("XTYP_REQUEST transaction\n");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_REQUEST);
if (!pXAct)
return NULL;
ATOM atom;
pXAct->u.request.hszItem = hszItem;
TRACE("XTYP_REQUEST transaction\n");
WDML_QueueTransaction(pConv, pXAct);
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) return NULL;
/* end advise loop: post WM_DDE_UNADVISE to server to terminate link
* on the specified item.
*/
if (!PostMessageA(pConv->hwndServer, WM_DDE_REQUEST, (WPARAM)pConv->hwndClient,
PackDDElParam(WM_DDE_REQUEST, wFmt, (UINT)hszItem)))
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, wFmt, hszItem);
if (!pXAct)
{
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pXAct);
GlobalDeleteAtom(atom);
return NULL;
}
pXAct->lParam = PackDDElParam(WM_DDE_REQUEST, wFmt, atom);
return pXAct;
}
......@@ -403,33 +493,49 @@ static WDML_XACT* WDML_QueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem)
*/
static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
{
DDEACK ddeAck;
UINT uiLo, uiHi;
WORD wStatus;
DDEACK ddeAck;
WINE_DDEHEAD wdh;
UINT uiLo, uiHi;
HSZ hsz;
if (msg->wParam != pConv->hwndServer)
return WDML_QS_PASS;
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
switch (msg->message)
{
case WM_DDE_ACK:
if (msg->wParam != pConv->hwndServer)
return WDML_QS_PASS;
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
wStatus = uiLo;
ddeAck = *((DDEACK*)&wStatus);
GlobalDeleteAtom(uiHi);
WDML_ExtractAck(uiLo, &ddeAck);
pXAct->hDdeData = 0;
if (ddeAck.fAck)
ERR("Positive answer should appear in NACK for a request, assuming negative\n");
TRACE("Negative answer...\n");
/* FIXME: billx: we should return 0 and post a negatve WM_DDE_ACK. */
break;
case WM_DDE_DATA:
if (msg->wParam != pConv->hwndServer)
return WDML_QS_PASS;
UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
TRACE("Got the result (%08lx)\n", (DWORD)uiLo);
if (DdeCmpStringHandles(uiHi, pXAct->u.request.hszItem) != 0)
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
return WDML_QS_PASS;
/* FIXME: memory clean up ? */
pXAct->hDdeData = WDML_Global2DataHandle((HGLOBAL)uiLo);
pXAct->hDdeData = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
if (wdh.fRelease)
{
GlobalFree((HGLOBAL)uiLo);
}
if (wdh.fAckReq)
{
WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, (HSZ)uiHi, msg->lParam,
WM_DDE_DATA);
}
else
{
GlobalDeleteAtom(uiHi);
}
break;
default:
......@@ -440,76 +546,105 @@ static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML
}
/******************************************************************
* WDML_QueueExecute
*
* WDML_BuildExecuteCommand
*
* Creates a DDE block suitable for sending in WM_DDE_COMMAND
* It also takes care of string conversion between the two window procedures
*/
static WDML_XACT* WDML_QueueExecute(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
static HGLOBAL WDML_BuildExecuteCommand(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
{
WDML_XACT* pXAct;
HGLOBAL hMem;
BOOL clientUnicode, serverUnicode;
DWORD memSize;
TRACE("XTYP_EXECUTE transaction\n");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_EXECUTE);
if (!pXAct)
return NULL;
clientUnicode = IsWindowUnicode(pConv->hwndClient);
serverUnicode = IsWindowUnicode(pConv->hwndServer);
if (cbData == (DWORD)-1)
if (clientUnicode == serverUnicode)
{
HDDEDATA hDdeData = (HDDEDATA)pData;
DWORD dwSize;
pData = DdeAccessData(hDdeData, &dwSize);
if (pData)
memSize = cbData;
}
else
{
if (clientUnicode)
{
pXAct->u.execute.hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dwSize);
if (pXAct->u.execute.hMem)
{
LPBYTE pDst;
memSize = WideCharToMultiByte( CP_ACP, 0, pData, cbData, NULL, 0, NULL, NULL);
}
else
{
memSize = MultiByteToWideChar( CP_ACP, 0, pData, cbData, NULL, 0);
}
}
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, memSize);
if (hMem)
{
LPBYTE pDst;
pDst = GlobalLock(pXAct->u.execute.hMem);
if (pDst)
pDst = GlobalLock(hMem);
if (pDst)
{
if (clientUnicode == serverUnicode)
{
memcpy(pDst, pData, cbData);
}
else
{
if (clientUnicode)
{
memcpy(pDst, pData, dwSize);
GlobalUnlock(pXAct->u.execute.hMem);
WideCharToMultiByte( CP_ACP, 0, pData, cbData, pDst, memSize, NULL, NULL);
}
else
{
GlobalFree(pXAct->u.execute.hMem);
pXAct->u.execute.hMem = 0;
MultiByteToWideChar( CP_ACP, 0, pData, cbData, (LPWSTR)pDst, memSize);
}
}
DdeUnaccessData(hDdeData);
GlobalUnlock(hMem);
}
else
{
pXAct->u.execute.hMem = 0;
GlobalFree(hMem);
hMem = 0;
}
}
else
{
LPSTR ptr;
return hMem;
}
/******************************************************************
* WDML_ClientQueueExecute
*
*
*/
static WDML_XACT* WDML_ClientQueueExecute(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
{
WDML_XACT* pXAct;
TRACE("XTYP_EXECUTE transaction\n");
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
if (!pXAct)
return NULL;
pXAct->u.execute.hMem = GlobalAlloc(GHND | GMEM_DDESHARE, cbData);
ptr = GlobalLock(pXAct->u.execute.hMem);
if (ptr)
if (cbData == (DWORD)-1)
{
HDDEDATA hDdeData = (HDDEDATA)pData;
pData = DdeAccessData(hDdeData, &cbData);
if (pData)
{
memcpy(ptr, pData, cbData);
GlobalUnlock(pXAct->u.execute.hMem);
pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
DdeUnaccessData(hDdeData);
}
}
WDML_QueueTransaction(pConv, pXAct);
if (!PostMessageA(pConv->hwndServer, WM_DDE_EXECUTE, (WPARAM)pConv->hwndClient,
pXAct->u.execute.hMem))
else
{
GlobalFree(pXAct->u.execute.hMem);
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pXAct);
TRACE("Returning FALSE on XTYP_EXECUTE - PostMessage returned FALSE\n");
return NULL;
pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
}
pXAct->lParam = pXAct->hMem;
return pXAct;
}
......@@ -522,7 +657,6 @@ static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML
{
DDEACK ddeAck;
UINT uiLo, uiHi;
WORD wStatus;
if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
{
......@@ -532,69 +666,64 @@ static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam);
if (uiHi != pXAct->u.execute.hMem)
if (uiHi != pXAct->hMem)
{
return WDML_QS_PASS;
}
wStatus = uiLo;
ddeAck = *((DDEACK*)&wStatus);
WDML_ExtractAck(uiLo, &ddeAck);
if (!ddeAck.fAck)
{
GlobalFree(pXAct->u.execute.hMem);
GlobalFree(pXAct->hMem);
}
pXAct->hDdeData = (HDDEDATA)1;
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_QueuePoke
* WDML_ClientQueuePoke
*
*
*/
static WDML_XACT* WDML_QueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData,
UINT wFmt, HSZ hszItem)
static WDML_XACT* WDML_ClientQueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData,
UINT wFmt, HSZ hszItem)
{
WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_POKE transaction\n");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_POKE);
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) return NULL;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE, wFmt, hszItem);
if (!pXAct)
{
GlobalDeleteAtom(atom);
return NULL;
}
if (cbData == (DWORD)-1)
{
pXAct->u.poke.hMem = (HDDEDATA)pData;
pXAct->hMem = (HDDEDATA)pData;
}
else
{
DDEPOKE* ddePoke;
pXAct->u.poke.hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData);
ddePoke = GlobalLock(pXAct->u.poke.hMem);
pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData);
ddePoke = GlobalLock(pXAct->hMem);
if (ddePoke)
{
memcpy(ddePoke->Value, pData, cbData);
ddePoke->fRelease = FALSE; /* FIXME: app owned ? */
ddePoke->cfFormat = wFmt;
GlobalUnlock(pXAct->u.poke.hMem);
GlobalUnlock(pXAct->hMem);
}
}
pXAct->u.poke.hszItem = hszItem;
pXAct->lParam = PackDDElParam(WM_DDE_POKE, pXAct->hMem, atom);
WDML_QueueTransaction(pConv, pXAct);
if (!PostMessageA(pConv->hwndServer, WM_DDE_POKE, (WPARAM)pConv->hwndClient,
PackDDElParam(WM_DDE_POKE, pXAct->u.execute.hMem, hszItem)))
{
GlobalFree(pXAct->u.execute.hMem);
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pXAct);
TRACE("Returning FALSE on XTYP_POKE - PostMessage returned FALSE\n");
return NULL;
}
return pXAct;
}
......@@ -607,7 +736,7 @@ static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XA
{
DDEACK ddeAck;
UINT uiLo, uiHi;
WORD wStatus;
HSZ hsz;
if (msg->message != WM_DDE_ACK && msg->wParam != pConv->hwndServer)
{
......@@ -615,117 +744,124 @@ static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XA
}
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
if (uiHi != pXAct->u.poke.hszItem)
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
{
return WDML_QS_PASS;
}
FreeDDElParam(WM_DDE_ACK, msg->lParam);
GlobalDeleteAtom(uiHi);
WDML_ExtractAck(uiLo, &ddeAck);
GlobalFree(pXAct->hMem);
wStatus = uiLo;
ddeAck = *((DDEACK*)&wStatus);
if (!ddeAck.fAck)
{
GlobalFree(pXAct->u.poke.hMem);
}
pXAct->hDdeData = (HDDEDATA)TRUE;
return TRUE;
}
/******************************************************************
* WDML_ClientQueueTerminate
*
* Creates and queue an WM_DDE_TERMINATE transaction
*/
static WDML_XACT* WDML_ClientQueueTerminate(WDML_CONV* pConv)
{
WDML_XACT* pXAct;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
if (!pXAct)
return NULL;
pXAct->lParam = 0;
pConv->wStatus &= ~ST_CONNECTED;
return pXAct;
}
/******************************************************************
* WDML_HandleTerminateReply
*
* handles the reply to a terminate request
*/
static WDML_QUEUE_STATE WDML_HandleTerminateReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
{
if (msg->message != WM_DDE_TERMINATE)
{
/* FIXME: should delete data passed here */
return WDML_QS_SWALLOWED;
}
if (msg->wParam != pConv->hwndServer)
{
FIXME("hmmm shouldn't happen\n");
return WDML_QS_PASS;
}
if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
{
WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
}
WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_HandleReplyData
*
*
*/
static WDML_QUEUE_STATE WDML_HandleReplyData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
static WDML_QUEUE_STATE WDML_HandleIncomingData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
{
UINT uiLo, uiHi;
HDDEDATA hDdeDataIn, hDdeDataOut;
WDML_LINK* pLink;
UINT uiLo, uiHi;
HDDEDATA hDdeDataIn, hDdeDataOut;
WDML_LINK* pLink;
WINE_DDEHEAD wdh;
HSZ hsz;
TRACE("WM_DDE_DATA message received in the Client Proc!\n");
/* wParam -- sending window handle */
/* lParam -- hDdeData & item HSZ */
UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
/* billx:
* For hot link, data should be passed to its callback with
* XTYP_ADVDATA and callback should return the proper status.
*/
pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, hsz, wdh.cfFormat);
if (!pLink)
{
WDML_DecHSZ(pConv->instance, hsz);
return WDML_QS_PASS;
}
for (pLink = pConv->thisInstance->links[WDML_CLIENT_SIDE]; pLink != NULL; pLink = pLink->next)
if (hDdeDataIn != 0 && wdh.fAckReq)
{
if (DdeCmpStringHandles((HSZ)uiHi, pLink->hszItem) == 0)
{
BOOL fRelease = FALSE;
BOOL fAckReq = FALSE;
DDEDATA* pDdeData;
/* item in the advise loop */
pConv = WDML_GetConv(pLink->hConv);
if (pConv == NULL)
{
continue;
}
if ((pDdeData = GlobalLock(uiLo)) != NULL)
{
fRelease = pDdeData->fRelease;
fAckReq = pDdeData->fAckReq;
}
if (hDdeDataIn != 0)
{
if (fAckReq)
{
DDEACK ddeAck;
ddeAck.bAppReturnCode = 0;
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
ddeAck.fAck = TRUE;
if (msg->lParam) {
PostMessageA(pConv->hwndServer, WM_DDE_ACK, pConv->hwndClient,
ReuseDDElParam(msg->lParam, WM_DDE_DATA, WM_DDE_ACK,
*(WORD*)&ddeAck, (UINT)pLink->hszItem));
msg->lParam = 0L;
}
else
{
PostMessageA(pConv->hwndServer, WM_DDE_ACK, pConv->hwndClient,
PackDDElParam(WM_DDE_ACK, *(WORD*)&ddeAck, (UINT)pLink->hszItem));
}
}
}
hDdeDataOut = 0;
if (pConv->thisInstance->callback != NULL /*&& thisInstance->processID == GetCurrentProcessId() */)
{
TRACE("Calling the callback, type = XTYP_ADVDATA, CB = 0x%lx, hConv = 0x%lx\n",
(DWORD)pConv->thisInstance->callback, (DWORD)pLink->hConv);
hDdeDataOut = (pConv->thisInstance->callback)(XTYP_ADVDATA,
pLink->uFmt,
pLink->hConv,
pConv->hszTopic,
pLink->hszItem,
hDdeDataIn,
0, 0);
if (hDdeDataOut == (HDDEDATA)DDE_FACK)
{
pLink->hDdeData = hDdeDataIn;
}
}
#if 0
if (fRelease)
{
DdeFreeDataHandle(hDdeDataIn);
}
#endif
break;
}
WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi,
msg->lParam, WM_DDE_DATA);
if (msg->lParam)
msg->lParam = 0;
}
else
{
GlobalDeleteAtom(uiHi);
}
hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv,
pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0);
if (hDdeDataOut == (HDDEDATA)DDE_FACK)
{
pLink->hDdeData = hDdeDataIn;
}
if (wdh.fRelease)
{
DdeFreeDataHandle(hDdeDataIn);
}
WDML_DecHSZ(pConv->instance, hsz);
if (msg->lParam)
FreeDDElParam(WM_DDE_DATA, msg->lParam);
......@@ -733,19 +869,28 @@ static WDML_QUEUE_STATE WDML_HandleReplyData(WDML_CONV* pConv, MSG* msg, HDDEDAT
}
/******************************************************************
* WDML_HandleReplyTerminate
* WDML_HandleIncomingTerminate
*
*
*/
static WDML_QUEUE_STATE WDML_HandleReplyTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
static WDML_QUEUE_STATE WDML_HandleIncomingTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
{
if ((LPARAM)pConv != msg->lParam)
if (pConv->hwndServer != (HWND)msg->wParam)
return WDML_QS_PASS;
/* billx: clean up the conv and associated links */
WDML_RemoveAllLinks(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE);
WDML_RemoveConv(pConv->thisInstance, WDML_CLIENT_SIDE, (HCONV)pConv);
DestroyWindow(msg->hwnd);
pConv->wStatus |= ST_TERMINATED;
if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
{
WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
}
if (pConv->wStatus & ST_CONNECTED)
{
/* don't care about result code (if server exists or not) */
PostMessageA(pConv->hwndServer, WM_DDE_TERMINATE, (WPARAM)pConv->hwndClient, 0L);
pConv->wStatus &= ~ST_CONNECTED;
}
/* have to keep connection around to allow reconnection */
return WDML_QS_HANDLED;
}
......@@ -756,7 +901,7 @@ static WDML_QUEUE_STATE WDML_HandleReplyTerminate(WDML_CONV* pConv, MSG* msg, HD
*/
static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
{
WDML_XACT* pXAct = pConv->transactions;
WDML_XACT* pXAct = pConv->transactions;
WDML_QUEUE_STATE qs;
if (pConv->transactions)
......@@ -779,6 +924,9 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h
case WM_DDE_POKE:
qs = WDML_HandlePokeReply(pConv, msg, pXAct);
break;
case WM_DDE_TERMINATE:
qs = WDML_HandleTerminateReply(pConv, msg, pXAct);
break;
default:
qs = WDML_QS_ERROR;
FIXME("oooch\n");
......@@ -793,6 +941,7 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h
switch (qs)
{
case WDML_QS_ERROR:
case WDML_QS_SWALLOWED:
*hdd = 0;
break;
case WDML_QS_HANDLED:
......@@ -800,39 +949,34 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h
* notify callback if asynchronous, and remove it in any case
*/
WDML_UnQueueTransaction(pConv, pXAct);
if (pXAct->dwTimeout == TIMEOUT_ASYNC)
if (pXAct->dwTimeout == TIMEOUT_ASYNC && pXAct->ddeMsg != WM_DDE_TERMINATE)
{
if (pConv->thisInstance->callback != NULL /*&& thisInstance->processID == GetCurrentProcessId() */)
{
TRACE("Calling the callback, type = XTYP_XACT_COMPLETE, CB = 0x%lx, hConv = 0x%lx\n",
(DWORD)pConv->thisInstance->callback, (DWORD)pConv);
(pConv->thisInstance->callback)(XTYP_XACT_COMPLETE, 0 /* FIXME */,
(HCONV)pConv,
pConv->hszTopic, 0 /* FIXME */,
pXAct->hDdeData,
MAKELONG(0, pXAct->xActID),
0 /* FIXME */);
qs = WDML_QS_PASS;
}
WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt,
(HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */);
qs = WDML_QS_PASS;
}
else
{
*hdd = pXAct->hDdeData;
}
WDML_FreeTransaction(pXAct);
WDML_FreeTransaction(pConv->instance, pXAct, FALSE); /* FIXME: should we free intermediate pmts ? */
break;
case WDML_QS_PASS:
/* no pending transaction found, try a warm link or a termination request */
switch (msg->message)
{
case WM_DDE_DATA:
qs = WDML_HandleReplyData(pConv, msg, hdd);
qs = WDML_HandleIncomingData(pConv, msg, hdd);
break;
case WM_DDE_TERMINATE:
qs = WDML_HandleReplyTerminate(pConv, msg, hdd);
qs = WDML_HandleIncomingTerminate(pConv, msg, hdd);
break;
}
break;
case WDML_QS_BLOCK:
FIXME("shouldn't be used on client side\n");
break;
}
return qs;
......@@ -846,7 +990,9 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h
*/
static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML_XACT* pXAct)
{
DWORD dwTime;
DWORD dwTime;
DWORD err;
WDML_CONV* pConv;
TRACE("Starting wait for a timeout of %ld ms\n", dwTimeout);
......@@ -855,21 +1001,23 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML
while ((dwTime = GetCurrentTime()) < dwTimeout)
{
/* we cannot hold the mutex all the time because when client and server run in a
/* we cannot be in the crit sect all the time because when client and server run in a
* single process they need to share the access to the internal data
*/
if (MsgWaitForMultipleObjects(0, NULL, FALSE,
dwTime - dwTimeout, QS_POSTMESSAGE) == WAIT_OBJECT_0 &&
WDML_WaitForMutex(handle_mutex))
dwTime - dwTimeout, QS_POSTMESSAGE) == WAIT_OBJECT_0)
{
BOOL ret = FALSE;
MSG msg;
WDML_CONV* pConv;
HDDEDATA hdd;
pConv = WDML_GetConv(hConv);
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv == NULL)
{
LeaveCriticalSection(&WDML_CritSect);
/* conversation no longer available... return failure */
break;
}
......@@ -881,7 +1029,7 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML
(pConv->transactions == NULL || ret);
if (ret) break;
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
LeaveCriticalSection(&WDML_CritSect);
if (ret)
{
return hdd;
......@@ -890,29 +1038,29 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML
}
TRACE("Timeout !!\n");
if (WDML_WaitForMutex(handle_mutex))
{
DWORD err;
WDML_CONV* pConv;
pConv = WDML_GetConv(hConv);
if (pConv == NULL)
{
return 0;
}
switch (pConv->transactions->ddeMsg)
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv != NULL)
{
if (pConv->transactions)
{
case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break;
case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break;
case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break;
case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break;
case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break;
default: err = DMLERR_INVALIDPARAMETER; break;
}
switch (pConv->transactions->ddeMsg)
{
case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break;
case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break;
case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break;
case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break;
case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break;
default: err = DMLERR_INVALIDPARAMETER; break;
}
pConv->thisInstance->lastError = err;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
pConv->instance->lastError = err;
}
}
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
......@@ -926,9 +1074,8 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
WDML_XACT* pXAct;
HDDEDATA hDdeData = 0;
TRACE("(0x%lx,%ld,0x%lx,0x%lx,%d,%d,%ld,0x%lx)\n",
(ULONG)pData,cbData,(DWORD)hConv,(DWORD)hszItem,wFmt,wType,
dwTimeout,(ULONG)pdwResult);
TRACE("(%p,%ld,0x%lx,0x%x,%d,%d,%ld,%p)\n",
pData, cbData, (DWORD)hConv, hszItem, wFmt, wType, dwTimeout, pdwResult);
if (hConv == 0)
{
......@@ -936,12 +1083,9 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
return 0;
}
if (!WDML_WaitForMutex(handle_mutex))
{
return FALSE;
}
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv);
pConv = WDML_GetConv(hConv, TRUE);
if (pConv == NULL)
{
/* cannot set error... cannot get back to DDE instance */
......@@ -953,13 +1097,13 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
case XTYP_EXECUTE:
if (hszItem != 0 || wFmt != 0)
{
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_QueueExecute(pConv, pData, cbData);
pXAct = WDML_ClientQueueExecute(pConv, pData, cbData);
break;
case XTYP_POKE:
pXAct = WDML_QueuePoke(pConv, pData, cbData, wFmt, hszItem);
pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem);
break;
case XTYP_ADVSTART|XTYPF_NODATA:
case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ:
......@@ -967,34 +1111,52 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
case XTYP_ADVSTART|XTYPF_ACKREQ:
if (pData)
{
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_QueueAdvise(pConv, wType, wFmt, hszItem);
pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem);
break;
case XTYP_ADVSTOP:
if (pData)
{
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_QueueUnadvise(pConv, wFmt, hszItem);
pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem);
break;
case XTYP_REQUEST:
if (pData)
{
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_QueueRequest(pConv, wFmt, hszItem);
pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem);
break;
default:
FIXME("Unknown transation\n");
/* unknown transaction type */
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER;
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
if (pXAct == NULL)
{
pConv->instance->lastError = DMLERR_MEMORY_ERROR;
goto theError;
}
WDML_QueueTransaction(pConv, pXAct);
if (!PostMessageA(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam))
{
TRACE("Failed posting message %d to 0x%04x (error=0x%lx)\n",
pXAct->ddeMsg, pConv->hwndServer, GetLastError());
pConv->wStatus &= ~ST_CONNECTED;
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
goto theError;
}
pXAct->dwTimeout = dwTimeout;
/* FIXME: should set the app bits on *pdwResult */
......@@ -1005,27 +1167,27 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
*pdwResult = MAKELONG(0, pXAct->xActID);
}
hDdeData = (HDDEDATA)1;
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
if (dwTimeout != TIMEOUT_ASYNC)
}
else
{
DWORD count = 0;
DWORD count, i;
if (pdwResult)
{
*pdwResult = 0L;
}
while (ReleaseMutex(handle_mutex))
count++;
count = WDML_CritSect.RecursionCount;
for (i = 0; i < count; i++)
LeaveCriticalSection(&WDML_CritSect);
hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct);
while (count-- != 0)
WDML_WaitForMutex(handle_mutex);
for (i = 0; i < count; i++)
EnterCriticalSection(&WDML_CritSect);
}
LeaveCriticalSection(&WDML_CritSect);
return hDdeData;
theError:
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
......@@ -1036,29 +1198,65 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
*/
static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
UINT uiLow, uiHi;
UINT uiLo, uiHi;
WDML_CONV* pConv = NULL;
HSZ hszSrv, hszTpc;
if (iMsg == WM_DDE_ACK &&
/* In response to WM_DDE_INITIATE, save server window */
UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi) &&
(WDML_CONV*)GetWindowLongA(hwnd, 4) == NULL)
UnpackDDElParam(WM_DDE_ACK, lParam, &uiLo, &uiHi) &&
/* in the initial WM_INITIATE sendmessage */
((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1))
{
WDML_INSTANCE* thisInstance = NULL;
WDML_CONV* pConv = NULL;
/* In response to WM_DDE_INITIATE, save server window */
char buf[256];
WDML_INSTANCE* pInstance;
FreeDDElParam(WM_DDE_ACK, lParam);
/* no converstation yet, add it */
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwnd, 0);
pConv = WDML_AddConv(thisInstance, WDML_CLIENT_SIDE, (HSZ)uiLow, (HSZ)uiHi,
/* FIXME: convlist should be handled here */
if (pConv)
{
/* we already have started the conv with a server, drop other replies */
GlobalDeleteAtom(uiLo);
GlobalDeleteAtom(uiHi);
return 0;
}
pInstance = WDML_GetInstanceFromWnd(hwnd);
hszSrv = WDML_MakeHszFromAtom(pInstance, uiLo);
hszTpc = WDML_MakeHszFromAtom(pInstance, uiHi);
pConv = WDML_AddConv(pInstance, WDML_CLIENT_SIDE, hszSrv, hszTpc,
hwnd, (HWND)wParam);
SetWindowLongA(hwnd, 4, (DWORD)pConv);
/* FIXME: so far we only use the first window in the list... */
return 0;
SetWindowLongA(hwnd, GWL_WDML_CONVERSATION, (DWORD)pConv);
pConv->wStatus |= ST_CONNECTED;
pConv->wConvst = XST_INIT1;
/* check if server is handled by DDEML */
if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) &&
strcmp(buf, WDML_szServerConvClassA) == 0) ||
(GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) &&
lstrcmpW((LPWSTR)buf, WDML_szServerConvClassW) == 0))
{
pConv->wStatus |= ST_ISLOCAL;
}
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_CONNECT_CONFIRM, hwnd, (HWND)wParam);
GlobalDeleteAtom(uiLo);
GlobalDeleteAtom(uiHi);
/* accept conversation */
return 1;
}
if ((iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST) && WDML_WaitForMutex(handle_mutex))
if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST)
{
WDML_CONV* pConv = (WDML_CONV*)GetWindowLongA(hwnd, 4);
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConvFromWnd(hwnd);
if (pConv)
{
......@@ -1073,14 +1271,14 @@ static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPA
WDML_HandleReply(pConv, &msg, &hdd);
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
return DefWindowProcA(hwnd, iMsg, wParam, lParam);
return (IsWindowUnicode(hwnd)) ?
DefWindowProcA(hwnd, iMsg, wParam, lParam) : DefWindowProcW(hwnd, iMsg, wParam, lParam);
}
/*****************************************************************
* DdeAbandonTransaction (USER32.@)
*/
......@@ -1090,6 +1288,57 @@ BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction
return TRUE;
}
/*****************************************************************
* DdeDisconnect (USER32.@)
*/
BOOL WINAPI DdeDisconnect(HCONV hConv)
{
WDML_CONV* pConv = NULL;
WDML_XACT* pXAct;
DWORD count, i;
BOOL ret = FALSE;
TRACE("(%ld)\n", (DWORD)hConv);
if (hConv == 0)
{
ERR("DdeDisconnect(): hConv = 0\n");
return FALSE;
}
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv != NULL)
{
if (pConv->wStatus & ST_CONNECTED)
{
if (pConv->wStatus & ST_CLIENT)
{
/* FIXME: should abandon all pending transactions */
pXAct = WDML_ClientQueueTerminate(pConv);
if (pXAct != NULL)
{
count = WDML_CritSect.RecursionCount;
for (i = 0; i < count; i++)
LeaveCriticalSection(&WDML_CritSect);
WDML_SyncWaitTransactionReply(hConv, 10000, pXAct);
for (i = 0; i < count; i++)
EnterCriticalSection(&WDML_CritSect);
ret = TRUE;
}
else
{
FIXME("Not implemented yet for a server side conversation\n");
}
}
}
/* still have to destroy data assosiated with conversation */
WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
}
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/*****************************************************************
* DdeImpersonateClient (USER32.@)
......@@ -1099,15 +1348,12 @@ BOOL WINAPI DdeImpersonateClient(HCONV hConv)
WDML_CONV* pConv;
BOOL ret = FALSE;
if (!WDML_WaitForMutex(handle_mutex))
{
return FALSE;
}
pConv = WDML_GetConv(hConv);
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, TRUE);
if (pConv)
{
ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer);
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
......@@ -15,27 +15,17 @@
/* defined in atom.c file.
*/
#define MAX_ATOM_LEN 255
/* Maximum buffer size ( including the '\0' ).
*/
#define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1)
/* 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 which instance
* of a given program is calling them. The API are supposed to
* associate the data to the instance that created it.
*/
/* The internal structures (prefixed by WDML) are used as follows:
* + a WDML_INSTANCE is created for each instance creation (DdeInitialize)
* - a popup windows (InstanceClass) is created for each instance. It will be
* used to receive all the DDEML events (server registration, conversation
* confirmation...)
* - a popup window (InstanceClass) is created for each instance.
* - this window is used to receive all the DDEML events (server registration,
* conversation confirmation...). See the WM_WDML_???? messages for details
* + when registring a server (DdeNameService) a WDML_SERVER is created
* - a popup window (ServerNameClass) is created
* + a conversation is represented by two WDML_CONV structures:
......@@ -47,6 +37,13 @@
* o a child window (of the ServerName) on the server side
* (ServerConvClass)
* - all the exchanges then take place between those two windows
* - windows for the conversation exist in two forms (Ansi & Unicode). This
* is only needed when a partner in a conv is not handled by DDEML. The
* type (A/W) of the window is used to handle the ansi <=> unicode
* transformations
* - two handles are created for a conversation (on each side). Each handle
* is linked to a structure. To help differentiate those handles, the
* local one has an even value, whereas the remote one has an odd value.
* + a (warm or link) is represented by two WDML_LINK structures:
* - one on client side, the other one on server side
* - therefore, two lists of links are kept for each instance
......@@ -55,67 +52,77 @@
* - offset 0: the DDE instance
* - offset 4: the current conversation (for ClientConv and ServerConv only)
*
* All the implementation (client & server) makes the assumption that the other side
* is not always a DDEML partner. However, if it's the case, supplementary services
* are available (most notably the REGISTER/UNREGISTER and CONNECT_CONFIRM messages
* to the callback function). To be correct in every situation, all the basic
* exchanges are made using the 'pure' DDE protocol. A (future !) enhancement would
* be to provide a new protocol in the case were both partners are handled by DDEML.
*
* The StringHandles are in fact stored as local atoms. So an HSZ and a (local) atom
* can be used interchangably. However, in order to keep track of the allocated HSZ,
* and to free them upon instance termination, all HSZ are stored in a link list.
* When the HSZ need to be passed thru DDE messages, we need to convert them back and
* forth to global atoms.
*/
/* this struct has the same mapping as all the DDE??? structures */
typedef struct {
unsigned short unused:12,
fResponse:1,
fRelease:1,
fDeferUpd:1,
fAckReq:1;
short cfFormat;
} WINE_DDEHEAD;
typedef struct tagHSZNode
{
struct tagHSZNode* next;
struct tagHSZNode* next;
HSZ hsz;
HSZ hsz2;
unsigned refCount;
} HSZNode;
typedef struct tagWDML_SERVER
{
struct tagWDML_SERVER* next;
HSZ hszService;
HSZ hszTopic;
HSZ hszServiceSpec;
ATOM atomService;
ATOM atomServiceSpec;
BOOL filterOn;
HWND hwndServer;
} WDML_SERVER;
typedef struct tagWDML_XACT {
struct tagWDML_XACT* next;
struct tagWDML_XACT* next; /* list of transactions in conversation */
DWORD xActID;
UINT ddeMsg;
HDDEDATA hDdeData;
DWORD dwTimeout;
DWORD hUser;
union {
struct {
UINT wType;
UINT wFmt;
HSZ hszItem;
HGLOBAL hDdeAdvise;
} advise;
struct {
UINT wFmt;
HSZ hszItem;
} unadvise;
struct {
HGLOBAL hMem;
} execute;
struct {
HGLOBAL hMem;
HSZ hszItem;
} poke;
struct {
HSZ hszItem;
} request;
} u;
UINT wType;
UINT wFmt;
HSZ hszItem;
ATOM atom; /* as converted from or to hszItem */
HGLOBAL hMem;
LPARAM lParam; /* useful for reusing */
} WDML_XACT;
typedef struct tagWDML_CONV
{
struct tagWDML_CONV* next; /* to link all the conversations */
struct tagWDML_INSTANCE* thisInstance;
struct tagWDML_INSTANCE* instance;
HSZ hszService; /* pmt used for connection */
HSZ hszTopic; /* pmt used for connection */
UINT afCmd; /* service name flag */
CONVCONTEXT convContext;
HWND hwndClient; /* source of conversation (ClientConvClass) */
HWND hwndServer; /* destination of conversation (ServerConvClass) */
WDML_XACT* transactions; /* pending transactions (client only) */
WDML_XACT* transactions; /* pending transactions */
DWORD hUser; /* user defined value */
DWORD wStatus; /* same bits as convinfo.wStatus */
DWORD wConvst; /* same values as convinfo.wConvst */
} WDML_CONV;
/* DDE_LINK struct defines hot, warm, and cold links */
......@@ -132,6 +139,7 @@ typedef struct tagWDML_INSTANCE
{
struct tagWDML_INSTANCE* next;
DWORD instanceID; /* needed to track monitor usage */
DWORD threadID; /* needed to keep instance linked to a unique thread */
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 */
......@@ -140,7 +148,6 @@ typedef struct tagWDML_INSTANCE
PFNCALLBACK callback;
DWORD CBFflags;
DWORD monitorFlags;
UINT txnCount; /* count transactions open to simplify closure */
DWORD lastError;
HWND hwndEvent;
WDML_SERVER* servers; /* list of registered servers */
......@@ -148,9 +155,7 @@ typedef struct tagWDML_INSTANCE
WDML_LINK* links[2]; /* active links for this instance (client and server) */
} WDML_INSTANCE;
extern WDML_INSTANCE* WDML_InstanceList; /* list of created instances, a process can create many */
extern DWORD WDML_MaxInstanceID; /* FIXME: OK for present, may have to worry about wrap-around later */
extern HANDLE handle_mutex;
extern CRITICAL_SECTION WDML_CritSect; /* protection for instance list */
/* header for the DDE Data objects */
typedef struct tagDDE_DATAHANDLE_HEAD
......@@ -163,46 +168,80 @@ typedef enum tagWDML_SIDE
WDML_CLIENT_SIDE = 0, WDML_SERVER_SIDE = 1
} WDML_SIDE;
/* server calls this. */
extern WDML_SERVER* WDML_AddServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic);
extern void WDML_RemoveServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic);
extern WDML_SERVER* WDML_FindServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic);
typedef enum {
WDML_QS_ERROR, WDML_QS_HANDLED, WDML_QS_PASS, WDML_QS_SWALLOWED, WDML_QS_BLOCK,
} WDML_QUEUE_STATE;
extern HDDEDATA WDML_InvokeCallback(WDML_INSTANCE* pInst, UINT uType, UINT uFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
DWORD dwData1, DWORD dwData2);
extern HDDEDATA WDML_InvokeCallback16(PFNCALLBACK pfn, UINT uType, UINT uFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
DWORD dwData1, DWORD dwData2);
extern WDML_SERVER* WDML_AddServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic);
extern void WDML_RemoveServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic);
extern WDML_SERVER* WDML_FindServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic);
/* called both in DdeClientTransaction and server side. */
extern WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
extern UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes, BOOL bUnicode, BOOL b16);
extern WDML_CONV* WDML_AddConv(WDML_INSTANCE* pInstance, WDML_SIDE side,
HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer);
extern void WDML_RemoveConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, HCONV hConv);
extern WDML_CONV* WDML_GetConv(HCONV hConv);
extern WDML_CONV* WDML_FindConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
extern void WDML_RemoveConv(WDML_CONV* pConv, WDML_SIDE side);
extern WDML_CONV* WDML_GetConv(HCONV hConv, BOOL checkConnected);
extern WDML_CONV* WDML_GetConvFromWnd(HWND hWnd);
extern WDML_CONV* WDML_FindConv(WDML_INSTANCE* pInstance, WDML_SIDE side,
HSZ hszService, HSZ hszTopic);
extern void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
extern LPARAM WDML_PostAck(WDML_CONV* pConv, WDML_SIDE side, WORD appRetCode,
BOOL fBusy, BOOL fAck, ATOM atom, LPARAM lParam, UINT oldMsg);
extern void WDML_AddLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
UINT wType, HSZ hszItem, UINT wFmt);
extern WDML_LINK* WDML_FindLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
extern WDML_LINK* WDML_FindLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
HSZ hszItem, UINT uFmt);
extern void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
extern void WDML_RemoveLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
HSZ hszItem, UINT wFmt);
extern void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side);
extern inline void WDML_ExtractAck(WORD status, DDEACK* da) {*da = *((DDEACK*)&status);}
extern void WDML_RemoveAllLinks(WDML_INSTANCE* pInstance, WDML_CONV* pConv, WDML_SIDE side);
/* string internals */
extern void WDML_FreeAllHSZ(WDML_INSTANCE* pInstance);
extern BOOL WDML_DecHSZ(WDML_INSTANCE* pInstance, HSZ hsz);
extern BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz);
extern ATOM WDML_MakeAtomFromHsz(HSZ hsz);
extern HSZ WDML_MakeHszFromAtom(WDML_INSTANCE* pInstance, ATOM atom);
/* client calls these */
extern WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg);
extern WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* pInstance, UINT ddeMsg, UINT wFmt, HSZ hszItem);
extern void WDML_QueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct);
extern BOOL WDML_UnQueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct);
extern void WDML_FreeTransaction(WDML_XACT* pXAct);
extern void WDML_FreeTransaction(WDML_INSTANCE* pInstance, WDML_XACT* pXAct, BOOL doFreePmt);
extern WDML_XACT* WDML_FindTransaction(WDML_CONV* pConv, DWORD tid);
extern HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease,
BOOL fDeferUpd, BOOL dAckReq);
extern HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem);
extern WDML_INSTANCE* WDML_FindInstance(DWORD InstId);
extern BOOL WDML_WaitForMutex(HANDLE mutex);
extern DWORD WDML_ReleaseMutex(HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m);
extern void WDML_FreeAllHSZ(WDML_INSTANCE* thisInstance);
extern void WDML_ReleaseAtom(WDML_INSTANCE* thisInstance, HSZ hsz);
extern void WDML_ReserveAtom(WDML_INSTANCE* thisInstance, HSZ hsz);
extern HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem, WINE_DDEHEAD* da);
extern WDML_INSTANCE* WDML_GetInstance(DWORD InstId);
extern WDML_INSTANCE* WDML_GetInstanceFromWnd(HWND hWnd);
/* broadcasting to DDE windows */
extern void WDML_BroadcastDDEWindows(const char* clsName, UINT uMsg,
WPARAM wParam, LPARAM lParam);
extern void WDML_NotifyThreadExit(DWORD tid);
extern const char WDML_szEventClass[]; /* class of window for events (aka instance) */
extern const char WDML_szEventClass[]; /* class of window for events (aka instance) */
extern const char WDML_szServerConvClassA[]; /* class of window for server side conv (ansi) */
extern const WCHAR WDML_szServerConvClassW[]; /* class of window for server side conv (unicode) */
extern const char WDML_szClientConvClassA[]; /* class of window for client side conv (ansi) */
extern const WCHAR WDML_szClientConvClassW[]; /* class of window for client side conv (unicode) */
#define WM_WDML_REGISTER (WM_USER + 0x200)
#define WM_WDML_UNREGISTER (WM_USER + 0x201)
#define WM_WDML_CONNECT_CONFIRM (WM_USER + 0x202)
/* parameters for messages:
* wParam lParam
* Register atom for service name atom for service spec
* Unregister atom for service name atom for service spec
* ConnectConfirm client window handle server window handle
*/
#define GWL_WDML_INSTANCE (0)
#define GWL_WDML_CONVERSATION (4)
#define GWL_WDML_SERVER (4)
#endif /* __WINE_DDEML_PRIVATE_H */
......@@ -19,6 +19,7 @@
#include "winerror.h"
#include "dde.h"
#include "ddeml.h"
#include "dde/dde_private.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(ddeml);
......@@ -54,6 +55,22 @@ typedef struct
CONVCONTEXT16 ConvCtxt;
} CONVINFO16, *LPCONVINFO16;
/* ### start build ### */
extern LONG CALLBACK WDML_CallTo16_long_llllllll (FARPROC16,LONG,LONG,LONG,LONG,LONG,LONG,LONG,LONG);
/* ### stop build ### */
/******************************************************************
* WDML_InvokeCallback16
*
*
*/
HDDEDATA WDML_InvokeCallback16(PFNCALLBACK pfn, UINT uType, UINT uFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
DWORD dwData1, DWORD dwData2)
{
return WDML_CallTo16_long_llllllll((FARPROC16)pfn, uType, uFmt, hConv,
hsz1, hsz2, hdata, dwData1, dwData2);
}
/******************************************************************************
* DdeInitialize (DDEML.2)
......@@ -61,8 +78,7 @@ typedef struct
UINT16 WINAPI DdeInitialize16(LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
DWORD afCmd, DWORD ulRes)
{
return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
afCmd, ulRes);
return WDML_Initialize(pidInst, (PFNCALLBACK)pfnCallback, afCmd, ulRes, FALSE, TRUE);
}
/*****************************************************************
......@@ -145,8 +161,7 @@ BOOL16 WINAPI DdeDisconnect16(HCONV hConv)
*/
BOOL16 WINAPI DdeSetUserHandle16(HCONV hConv, DWORD id, DWORD hUser)
{
FIXME("(%d,%ld,%ld): stub\n",hConv,id, hUser);
return 0;
return DdeSetUserHandle(hConv, id, hUser);
}
/*****************************************************************
......@@ -167,7 +182,9 @@ HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage)
if (codepage)
{
return DdeCreateStringHandleA(idInst, str, codepage);
} else {
}
else
{
TRACE("Default codepage supplied\n");
return DdeCreateStringHandleA(idInst, str, CP_WINANSI);
}
......@@ -178,7 +195,7 @@ HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage)
*/
BOOL16 WINAPI DdeFreeStringHandle16(DWORD idInst, HSZ hsz)
{
FIXME("idInst %ld hsz 0x%x\n",idInst,hsz);
TRACE("idInst %ld hsz 0x%x\n",idInst,hsz);
return (BOOL)DdeFreeStringHandle(idInst, hsz);
}
......@@ -218,8 +235,7 @@ HDDEDATA WINAPI DdeClientTransaction16(LPVOID pData, DWORD cbData,
BOOL16 WINAPI DdeAbandonTransaction16(DWORD idInst, HCONV hConv,
DWORD idTransaction)
{
FIXME("empty stub\n");
return TRUE;
return DdeAbandonTransaction(idInst, hConv, idTransaction);
}
/*****************************************************************
......@@ -256,7 +272,8 @@ DWORD WINAPI DdeGetData16(
*/
LPBYTE WINAPI DdeAccessData16(HDDEDATA hData, LPDWORD pcbDataSize)
{
return DdeAccessData(hData, pcbDataSize);
/* FIXME: there's a memory leak here... */
return (LPBYTE)MapLS(DdeAccessData(hData, pcbDataSize));
}
/*****************************************************************
......@@ -264,7 +281,7 @@ LPBYTE WINAPI DdeAccessData16(HDDEDATA hData, LPDWORD pcbDataSize)
*/
BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData)
{
return DdeUnaccessData(hData);
return DdeUnaccessData(hData);
}
/*****************************************************************
......@@ -272,7 +289,7 @@ BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData)
*/
BOOL16 WINAPI DdeEnableCallback16(DWORD idInst, HCONV hConv, UINT16 wCmd)
{
return DdeEnableCallback(idInst, hConv, wCmd);
return DdeEnableCallback(idInst, hConv, wCmd);
}
/*****************************************************************
......@@ -281,7 +298,7 @@ BOOL16 WINAPI DdeEnableCallback16(DWORD idInst, HCONV hConv, UINT16 wCmd)
HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2,
UINT16 afCmd)
{
return DdeNameService(idInst, hsz1, hsz2, afCmd);
return DdeNameService(idInst, hsz1, hsz2, afCmd);
}
/*****************************************************************
......@@ -289,7 +306,7 @@ HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2,
*/
UINT16 WINAPI DdeGetLastError16(DWORD idInst)
{
return (UINT16)DdeGetLastError(idInst);
return (UINT16)DdeGetLastError(idInst);
}
/*****************************************************************
......@@ -297,7 +314,7 @@ UINT16 WINAPI DdeGetLastError16(DWORD idInst)
*/
INT16 WINAPI DdeCmpStringHandles16(HSZ hsz1, HSZ hsz2)
{
return DdeCmpStringHandles(hsz1, hsz2);
return DdeCmpStringHandles(hsz1, hsz2);
}
/******************************************************************
......
......@@ -11,6 +11,7 @@
*/
#include <string.h>
#include <stdio.h>
#include "winbase.h"
#include "windef.h"
#include "wingdi.h"
......@@ -23,18 +24,16 @@
DEFAULT_DEBUG_CHANNEL(ddeml);
WDML_INSTANCE* WDML_InstanceList = NULL;
DWORD WDML_MaxInstanceID = 0; /* OK for present, may have to worry about wrap-around later */
static const char DDEInstanceAccess[] = "DDEMaxInstance";
static const char DDEHandleAccess[] = "DDEHandleAccess";
HANDLE handle_mutex = 0;
static WDML_INSTANCE* WDML_InstanceList = NULL;
static DWORD WDML_MaxInstanceID = 0; /* OK for present, have to worry about wrap-around later */
const char WDML_szEventClass[] = "DdeEventClass";
CRITICAL_SECTION WDML_CritSect = CRITICAL_SECTION_INIT;
/* FIXME
* currently the msg parameter is not used in the packing functions.
* it should be used to identify messages which don't actually require the packing operation
* but would do with the simple DWORD for lParam
*/
/* ================================================================
*
* Pure DDE (non DDEML) management
*
* ================================================================ */
static BOOL DDE_RequirePacking(UINT msg)
{
......@@ -218,11 +217,11 @@ LPARAM WINAPI ReuseDDElParam(LPARAM lParam, UINT msgIn, UINT msgOut,
/*****************************************************************
* ImpersonateDdeClientWindow (USER32.@)
*
* PARAMS
* hWndClient [I] handle to DDE client window
* hWndServer [I] handle to DDE server window
*/
BOOL WINAPI ImpersonateDdeClientWindow(
HWND hWndClient, /* [in] handle to DDE client window */
HWND hWndServer /* [in] handle to DDE server window */
)
BOOL WINAPI ImpersonateDdeClientWindow(HWND hWndClient, HWND hWndServer)
{
FIXME("(%04x %04x): stub\n", hWndClient, hWndServer);
return FALSE;
......@@ -239,188 +238,153 @@ BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, CONST SECURITY_QUALITY_OF_SE
return TRUE;
}
/* ================================================================
*
* Instance management
*
* ================================================================ */
/******************************************************************************
* IncrementInstanceId
*
* generic routine to increment the max instance Id and allocate a new application instance
*/
static DWORD WDML_IncrementInstanceId(WDML_INSTANCE* thisInstance)
static void WDML_IncrementInstanceId(WDML_INSTANCE* pInstance)
{
DWORD id = InterlockedIncrement(&WDML_MaxInstanceID);
thisInstance->instanceID = id;
pInstance->instanceID = id;
TRACE("New instance id %ld allocated\n", id);
return DMLERR_NO_ERROR;
}
/******************************************************************************
* DdeInitializeA (USER32.@)
/******************************************************************
* WDML_EventProc
*
*
*/
UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes)
{
UINT ret = DdeInitializeW(pidInst, pfnCallback, afCmd, ulRes);
if (ret == DMLERR_NO_ERROR) {
WDML_INSTANCE* thisInstance = WDML_FindInstance(*pidInst);
if (thisInstance)
thisInstance->unicode = FALSE;
}
return ret;
}
static LRESULT CALLBACK WDML_EventProc(HWND hwndEvent, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WDML_INSTANCE* thisInstance;
HDDEDATA hDdeData;
WDML_INSTANCE* pInstance;
HSZ hsz1, hsz2;
switch (uMsg)
{
case WM_WDML_REGISTER:
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndEvent, 0);
pInstance = WDML_GetInstanceFromWnd(hwndEvent);
/* try calling the Callback */
if (thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId()*/)
if (pInstance && !(pInstance->CBFflags & CBF_SKIP_REGISTRATIONS))
{
TRACE("Calling the callback, type=XTYP_REGISTER, CB=0x%lx\n",
(DWORD)thisInstance->callback);
hDdeData = (thisInstance->callback)(XTYP_REGISTER, 0, 0,
(HSZ)wParam, (HSZ)lParam, 0, 0, 0);
TRACE("Callback function called - result=%d\n", (INT)hDdeData);
hsz1 = WDML_MakeHszFromAtom(pInstance, wParam);
hsz2 = WDML_MakeHszFromAtom(pInstance, lParam);
WDML_InvokeCallback(pInstance, XTYP_REGISTER, 0, 0, hsz1, hsz2, 0, 0, 0);
WDML_DecHSZ(pInstance, hsz1);
WDML_DecHSZ(pInstance, hsz2);
}
break;
case WM_WDML_UNREGISTER:
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndEvent, 0);
if (thisInstance && thisInstance->callback != NULL)
pInstance = WDML_GetInstanceFromWnd(hwndEvent);
if (pInstance && !(pInstance->CBFflags & CBF_SKIP_UNREGISTRATIONS))
{
hsz1 = WDML_MakeHszFromAtom(pInstance, wParam);
hsz2 = WDML_MakeHszFromAtom(pInstance, lParam);
WDML_InvokeCallback(pInstance, XTYP_UNREGISTER, 0, 0, hsz1, hsz2, 0, 0, 0);
WDML_DecHSZ(pInstance, hsz1);
WDML_DecHSZ(pInstance, hsz2);
}
break;
case WM_WDML_CONNECT_CONFIRM:
pInstance = WDML_GetInstanceFromWnd(hwndEvent);
if (pInstance && !(pInstance->CBFflags & CBF_SKIP_CONNECT_CONFIRMS))
{
if (thisInstance->CBFflags & CBF_SKIP_DISCONNECTS)
WDML_CONV* pConv;
/* confirm connection...
* lookup for this conv handle
*/
for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConv->next)
{
FIXME("skip callback XTYP_UNREGISTER\n");
if (pConv->hwndClient == (HWND)wParam && pConv->hwndServer == (HWND)lParam)
break;
}
else
if (pConv)
{
TRACE("calling callback XTYP_UNREGISTER, idInst=%ld\n",
thisInstance->instanceID);
(thisInstance->callback)(XTYP_UNREGISTER, 0, 0,
(HSZ)wParam, (HSZ)lParam, 0, 0, 0);
pConv->wStatus |= ST_ISLOCAL;
WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv,
pConv->hszTopic, pConv->hszService, 0, 0,
(pConv->wStatus & ST_ISSELF) ? 1 : 0);
}
}
break;
default:
return DefWindowProcA(hwndEvent, uMsg, wParam, lParam);
}
return DefWindowProcA(hwndEvent, uMsg, wParam, lParam);
return 0;
}
/******************************************************************************
* DdeInitializeW [USER32.@]
* Registers an application with the DDEML
/******************************************************************
* WDML_Initialize
*
* PARAMS
* pidInst [I] Pointer to instance identifier
* pfnCallback [I] Pointer to callback function
* afCmd [I] Set of command and filter flags
* ulRes [I] Reserved
*
* RETURNS
* Success: DMLERR_NO_ERROR
* Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
*/
UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes)
UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes, BOOL bUnicode, BOOL b16)
{
/* probably not really capable of handling multiple processes, but should handle
* multiple instances within one process */
SECURITY_ATTRIBUTES s_attrib;
DWORD err_no = 0;
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
WDML_INSTANCE* reference_inst;
UINT ret;
WNDCLASSEXA wndclass;
TRACE("(%p,%p,0x%lx,%ld)\n",
pidInst, pfnCallback, afCmd, ulRes);
if (ulRes)
{
ERR("Reserved value not zero? What does this mean?\n");
FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
afCmd,ulRes);
/* trap this and no more until we know more */
return DMLERR_NO_ERROR;
}
if (!pfnCallback)
{
/* this one may be wrong - MS dll seems to accept the condition,
leave this until we find out more !! */
/* can't set up the instance with nothing to act as a callback */
TRACE("No callback provided\n");
return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
}
/* grab enough heap for one control struct - not really necessary for re-initialise
* but allows us to use same validation routines */
thisInstance = (WDML_INSTANCE*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE));
if (thisInstance == NULL)
pInstance = (WDML_INSTANCE*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE));
if (pInstance == NULL)
{
/* catastrophe !! warn user & abort */
ERR("Instance create failed - out of memory\n");
return DMLERR_SYS_ERROR;
}
thisInstance->next = NULL;
thisInstance->monitor = (afCmd | APPCLASS_MONITOR);
pInstance->next = NULL;
pInstance->monitor = (afCmd | APPCLASS_MONITOR);
/* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
thisInstance->clientOnly = afCmd & APPCMD_CLIENTONLY;
thisInstance->instanceID = *pidInst; /* May need to add calling proc Id */
thisInstance->callback = *pfnCallback;
thisInstance->txnCount = 0;
thisInstance->unicode = TRUE;
thisInstance->win16 = FALSE;
thisInstance->nodeList = NULL; /* node will be added later */
thisInstance->monitorFlags = afCmd & MF_MASK;
thisInstance->servers = NULL;
thisInstance->convs[0] = NULL;
thisInstance->convs[1] = NULL;
thisInstance->links[0] = NULL;
thisInstance->links[1] = NULL;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_EventProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WDML_szEventClass;
wndclass.hIconSm = 0;
RegisterClassExA(&wndclass);
thisInstance->hwndEvent = CreateWindowA(WDML_szEventClass, NULL,
WS_POPUP, 0, 0, 0, 0,
0, 0, 0, 0);
SetWindowLongA(thisInstance->hwndEvent, 0, (DWORD)thisInstance);
pInstance->clientOnly = afCmd & APPCMD_CLIENTONLY;
pInstance->instanceID = *pidInst; /* May need to add calling proc Id */
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->servers = NULL;
pInstance->convs[0] = NULL;
pInstance->convs[1] = NULL;
pInstance->links[0] = NULL;
pInstance->links[1] = NULL;
/* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
thisInstance->CBFflags = afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
pInstance->CBFflags = afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
if (!thisInstance->clientOnly)
if (!pInstance->clientOnly)
{
/* Check for other way of setting Client-only !! */
thisInstance->clientOnly =
(thisInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS;
pInstance->clientOnly =
(pInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS;
}
TRACE("instance created - checking validity \n");
......@@ -429,30 +393,13 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
{
/* Initialisation of new Instance Identifier */
TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
/* Need to set up Mutex in case it is not already present */
s_attrib.bInheritHandle = TRUE;
s_attrib.lpSecurityDescriptor = NULL;
s_attrib.nLength = sizeof(s_attrib);
handle_mutex = CreateMutexA(&s_attrib,0,DDEHandleAccess);
if (!handle_mutex)
{
ERR("CreateMutex failed - handle list %li\n",GetLastError());
HeapFree(GetProcessHeap(), 0, thisInstance);
return DMLERR_SYS_ERROR;
}
}
if (!WDML_WaitForMutex(handle_mutex))
{
return DMLERR_SYS_ERROR;
}
EnterCriticalSection(&WDML_CritSect);
if (WDML_InstanceList == NULL)
{
/* can't be another instance in this case, assign to the base pointer */
WDML_InstanceList = thisInstance;
WDML_InstanceList = pInstance;
/* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
* present
......@@ -463,11 +410,10 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
* first call for a given callback !!!
*/
thisInstance->CBFflags = thisInstance->CBFflags|APPCMD_FILTERINITS;
pInstance->CBFflags = pInstance->CBFflags|APPCMD_FILTERINITS;
TRACE("First application instance detected OK\n");
/* allocate new instance ID */
if ((err_no = WDML_IncrementInstanceId(thisInstance))) return err_no;
WDML_IncrementInstanceId(pInstance);
}
else
{
......@@ -484,27 +430,27 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
* clever (lazy ?) it will fail to pick up that later calls are for
* the same application - should we trust them ?
*/
if (thisInstance->instanceID == reference_inst->instanceID)
if (pInstance->instanceID == reference_inst->instanceID)
{
/* Check 1 - must be same Client-only state */
/* Check 1 - must be same Client-only state */
if (thisInstance->clientOnly != reference_inst->clientOnly)
if (pInstance->clientOnly != reference_inst->clientOnly)
{
ret = DMLERR_DLL_USAGE;
goto theError;
}
/* Check 2 - cannot use 'Monitor' with any non-monitor modes */
/* Check 2 - cannot use 'Monitor' with any non-monitor modes */
if (thisInstance->monitor != reference_inst->monitor)
if (pInstance->monitor != reference_inst->monitor)
{
ret = DMLERR_INVALIDPARAMETER;
goto theError;
}
/* Check 3 - must supply different callback address */
/* Check 3 - must supply different callback address */
if (thisInstance->callback == reference_inst->callback)
if (pInstance->callback == reference_inst->callback)
{
ret = DMLERR_DLL_USAGE;
goto theError;
......@@ -515,30 +461,50 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
/* All cleared, add to chain */
TRACE("Application Instance checks finished\n");
if ((err_no = WDML_IncrementInstanceId(thisInstance))) return err_no;
reference_inst->next = thisInstance;
WDML_IncrementInstanceId(pInstance);
reference_inst->next = pInstance;
}
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return DMLERR_SYS_ERROR;
*pidInst = thisInstance->instanceID;
LeaveCriticalSection(&WDML_CritSect);
*pidInst = pInstance->instanceID;
/* for deadlock issues, windows must always be created when outside the critical section */
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_EventProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WDML_szEventClass;
wndclass.hIconSm = 0;
RegisterClassExA(&wndclass);
pInstance->hwndEvent = CreateWindowA(WDML_szEventClass, NULL,
WS_POPUP, 0, 0, 0, 0,
0, 0, 0, 0);
SetWindowLongA(pInstance->hwndEvent, GWL_WDML_INSTANCE, (DWORD)pInstance);
TRACE("New application instance processing finished OK\n");
}
else
{
/* Reinitialisation situation --- FIX */
TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback, afCmd, ulRes);
if (!WDML_WaitForMutex(handle_mutex))
{
HeapFree(GetProcessHeap(), 0, thisInstance);
return DMLERR_SYS_ERROR;
}
EnterCriticalSection(&WDML_CritSect);
if (WDML_InstanceList == NULL)
{
ret = DMLERR_DLL_USAGE;
goto theError;
}
HeapFree(GetProcessHeap(), 0, thisInstance); /* finished - release heap space used as work store */
HeapFree(GetProcessHeap(), 0, pInstance); /* finished - release heap space used as work store */
/* can't reinitialise if we have initialised nothing !! */
reference_inst = WDML_InstanceList;
/* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
......@@ -567,7 +533,7 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
}
/* Check 2 - cannot change monitor modes */
if (thisInstance->monitor != reference_inst->monitor)
if (pInstance->monitor != reference_inst->monitor)
{
ret = DMLERR_DLL_USAGE;
goto theError;
......@@ -593,26 +559,50 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
ret = DMLERR_INVALIDPARAMETER;
goto theError;
}
/* All checked - change relevant flags */
/* All checked - change relevant flags */
reference_inst->CBFflags = thisInstance->CBFflags;
reference_inst->clientOnly = thisInstance->clientOnly;
reference_inst->monitorFlags = thisInstance->monitorFlags;
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE))
{
HeapFree(GetProcessHeap(), 0, thisInstance);
return DMLERR_SYS_ERROR;
}
reference_inst->CBFflags = pInstance->CBFflags;
reference_inst->clientOnly = pInstance->clientOnly;
reference_inst->monitorFlags = pInstance->monitorFlags;
LeaveCriticalSection(&WDML_CritSect);
}
return DMLERR_NO_ERROR;
theError:
HeapFree(GetProcessHeap(), 0, thisInstance);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", 0))
return DMLERR_SYS_ERROR;
HeapFree(GetProcessHeap(), 0, pInstance);
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/******************************************************************************
* DdeInitializeA (USER32.@)
*/
UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes)
{
return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, FALSE, FALSE);
}
/******************************************************************************
* DdeInitializeW [USER32.@]
* Registers an application with the DDEML
*
* PARAMS
* pidInst [I] Pointer to instance identifier
* pfnCallback [I] Pointer to callback function
* afCmd [I] Set of command and filter flags
* ulRes [I] Reserved
*
* RETURNS
* Success: DMLERR_NO_ERROR
* Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
*/
UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes)
{
return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE, FALSE);
}
/*****************************************************************
* DdeUninitialize [USER32.@] Frees DDEML resources
*
......@@ -628,386 +618,408 @@ BOOL WINAPI DdeUninitialize(DWORD idInst)
{
/* Stage one - check if we have a handle for this instance
*/
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
WDML_INSTANCE* reference_inst;
WDML_CONV* pConv;
WDML_CONV* pConvNext;
EnterCriticalSection(&WDML_CritSect);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
return TRUE;
}
if (!WDML_WaitForMutex(handle_mutex))
{
return DMLERR_SYS_ERROR;
}
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL)
pInstance = WDML_GetInstance(idInst);
if (pInstance == NULL)
{
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return FALSE;
LeaveCriticalSection(&WDML_CritSect);
/*
* Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/
return FALSE;
}
FIXME("(%ld): partial stub\n", idInst);
/* FIXME ++++++++++++++++++++++++++++++++++++++++++
* Needs to de-register all service names
*
/* first terminate all conversations client side
* this shall close existing links...
*/
for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv != NULL; pConv = pConvNext)
{
pConvNext = pConv->next;
DdeDisconnect((HCONV)pConv);
}
if (pInstance->convs[WDML_CLIENT_SIDE])
FIXME("still pending conversations\n");
/* then unregister all known service names */
DdeNameService(idInst, 0, 0, DNS_UNREGISTER);
/* Free the nodes that were not freed by this instance
* and remove the nodes from the list of HSZ nodes.
*/
WDML_FreeAllHSZ(thisInstance);
WDML_FreeAllHSZ(pInstance);
DestroyWindow(thisInstance->hwndEvent);
DestroyWindow(pInstance->hwndEvent);
/* OK now delete the instance handle itself */
if (WDML_InstanceList == thisInstance)
if (WDML_InstanceList == pInstance)
{
/* special case - the first/only entry
*/
WDML_InstanceList = thisInstance->next;
WDML_InstanceList = pInstance->next;
}
else
{
/* general case
*/
reference_inst = WDML_InstanceList;
while (reference_inst->next != thisInstance)
while (reference_inst->next != pInstance)
{
reference_inst = thisInstance->next;
reference_inst = pInstance->next;
}
reference_inst->next = thisInstance->next;
reference_inst->next = pInstance->next;
}
/* release the mutex and the heap entry
/* leave crit sect and release the heap entry
*/
HeapFree(GetProcessHeap(), 0, thisInstance);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE))
{
/* should record something here, but nothing left to hang it from !!
*/
return FALSE;
}
HeapFree(GetProcessHeap(), 0, pInstance);
LeaveCriticalSection(&WDML_CritSect);
return TRUE;
}
/******************************************************************************
* RemoveHSZNodes (INTERNAL)
/******************************************************************
* WDML_NotifyThreadExit
*
*
* Remove a node from the list of HSZ nodes.
*/
static void WDML_RemoveHSZNode(WDML_INSTANCE* thisInstance, HSZ hsz)
void WDML_NotifyThreadDetach(void)
{
HSZNode* pPrev = NULL;
HSZNode* pCurrent = NULL;
/* Set the current node at the start of the list.
*/
pCurrent = thisInstance->nodeList;
/* While we have more nodes.
*/
while (pCurrent != NULL)
WDML_INSTANCE* pInstance;
WDML_INSTANCE* next;
DWORD tid = GetCurrentThreadId();
EnterCriticalSection(&WDML_CritSect);
for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = next)
{
/* If we found the node we were looking for.
*/
if (pCurrent->hsz == hsz)
next = pInstance->next;
if (pInstance->threadID == tid)
{
/* 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 == thisInstance->nodeList)
{
thisInstance->nodeList = 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.
*/
HeapFree(GetProcessHeap(), 0, pCurrent);
break;
DdeUninitialize(pInstance->instanceID);
}
/* Save the previous node pointer.
*/
pPrev = pCurrent;
/* Move on to the next node.
*/
pCurrent = pCurrent->next;
}
LeaveCriticalSection(&WDML_CritSect);
}
/******************************************************************************
* FreeAndRemoveHSZNodes (INTERNAL)
/******************************************************************
* WDML_InvokeCallback
*
* Frees up all the strings still allocated in the list and
* remove all the nodes from the list of HSZ nodes.
*/
void WDML_FreeAllHSZ(WDML_INSTANCE* thisInstance)
{
/* Free any strings created in this instance.
*/
while (thisInstance->nodeList != NULL)
{
DdeFreeStringHandle(thisInstance->instanceID, thisInstance->nodeList->hsz);
}
}
/******************************************************************************
* GetSecondaryHSZValue (INTERNAL)
*
* Insert a node to the head of the list.
*/
static HSZ WDML_GetSecondaryHSZValue(WDML_INSTANCE* thisInstance, HSZ hsz)
HDDEDATA WDML_InvokeCallback(WDML_INSTANCE* pInstance, UINT uType, UINT uFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
DWORD dwData1, DWORD dwData2)
{
HSZ hsz2 = 0;
if (hsz != 0)
HDDEDATA ret;
if (pInstance == NULL)
return (HDDEDATA)0;
TRACE("invoking CB%d[%08lx] (%u %u %08lx 0x%x 0x%x %u %lu %lu)\n",
pInstance->win16 ? 16 : 32, (DWORD)pInstance->callback, uType, uFmt,
(DWORD)hConv, hsz1, hsz2, hdata, dwData1, dwData2);
if (pInstance->win16)
{
/* Create and set the Secondary handle */
if (thisInstance->unicode)
{
WCHAR wSecondaryString[MAX_BUFFER_LEN];
WCHAR wUniqueNum[MAX_BUFFER_LEN];
if (DdeQueryStringW(thisInstance->instanceID, hsz,
wSecondaryString,
MAX_BUFFER_LEN, CP_WINUNICODE))
{
static const WCHAR format[] = {'(','%','l','d',')',0};
wsprintfW(wUniqueNum, format,
(DWORD)thisInstance->instanceID);
lstrcatW(wSecondaryString, wUniqueNum);
hsz2 = GlobalAddAtomW(wSecondaryString);
}
}
else
{
CHAR SecondaryString[MAX_BUFFER_LEN];
CHAR UniqueNum[MAX_BUFFER_LEN];
if (DdeQueryStringA(thisInstance->instanceID, hsz,
SecondaryString,
MAX_BUFFER_LEN, CP_WINANSI))
{
wsprintfA(UniqueNum,"(%ld)", thisInstance->instanceID);
lstrcatA(SecondaryString, UniqueNum);
hsz2 = GlobalAddAtomA(SecondaryString);
}
}
ret = WDML_InvokeCallback16(pInstance->callback, uType, uFmt, hConv,
hsz1, hsz2, hdata, dwData1, dwData2);
}
return hsz2;
}
/******************************************************************************
* InsertHSZNode (INTERNAL)
*
* Insert a node to the head of the list.
*/
static void WDML_InsertHSZNode(WDML_INSTANCE* thisInstance, HSZ hsz)
{
if (hsz != 0)
else
{
HSZNode* pNew = NULL;
/* Create a new node for this HSZ.
*/
pNew = (HSZNode*)HeapAlloc(GetProcessHeap(), 0, sizeof(HSZNode));
if (pNew != NULL)
{
/* Set the handle value.
*/
pNew->hsz = hsz;
/* Create and set the Secondary handle */
pNew->hsz2 = WDML_GetSecondaryHSZValue(thisInstance, hsz);
/* Attach the node to the head of the list. i.e most recently added is first
*/
pNew->next = thisInstance->nodeList;
/* The new node is now at the head of the list
* so set the global list pointer to it.
*/
thisInstance->nodeList = pNew;
}
else
{
ERR("Primary HSZ Node allocation failed - out of memory\n");
}
ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2);
}
TRACE("done => %08lx\n", (DWORD)ret);
return ret;
}
/*****************************************************************************
* Find_Instance_Entry
* WDML_GetInstance
*
* generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
* for an instance Id, or NULL if the entry does not exist
*
* ASSUMES the mutex protecting the handle entry list is reserved before calling
*/
WDML_INSTANCE* WDML_FindInstance(DWORD InstId)
WDML_INSTANCE* WDML_GetInstance(DWORD instId)
{
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
thisInstance = WDML_InstanceList;
while (thisInstance != NULL)
for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = pInstance->next)
{
if (thisInstance->instanceID == InstId)
if (pInstance->instanceID == instId)
{
return thisInstance;
if (GetCurrentThreadId() != pInstance->threadID)
{
FIXME("Tried to get instance from wrong thread\n");
continue;
}
return pInstance;
}
thisInstance = thisInstance->next;
}
TRACE("Instance entry missing\n");
return NULL;
}
/******************************************************************************
* WDML_ReleaseMutex
/******************************************************************
* WDML_GetInstanceFromWnd
*
*
* generic routine to release a reserved mutex
*/
DWORD WDML_ReleaseMutex(HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m)
WDML_INSTANCE* WDML_GetInstanceFromWnd(HWND hWnd)
{
if (!ReleaseMutex(mutex))
{
ERR("ReleaseMutex failed - %s mutex %li\n", mutex_name, GetLastError());
if (release_handle_m)
{
ReleaseMutex(handle_mutex);
}
return DMLERR_SYS_ERROR;
}
return DMLERR_NO_ERROR;
return (WDML_INSTANCE*)GetWindowLongA(hWnd, GWL_WDML_INSTANCE);
}
/******************************************************************************
* WDML_WaitForMutex
* DdeGetLastError [USER32.@] Gets most recent error code
*
* PARAMS
* idInst [I] Instance identifier
*
* generic routine to wait for the mutex
* RETURNS
* Last error code
*/
BOOL WDML_WaitForMutex(HANDLE mutex)
UINT WINAPI DdeGetLastError(DWORD idInst)
{
DWORD result;
DWORD error_code;
WDML_INSTANCE* pInstance;
FIXME("(%ld): error reporting is weakly implemented\n", idInst);
result = WaitForSingleObject(mutex, INFINITE);
EnterCriticalSection(&WDML_CritSect);
/* both errors should never occur */
if (WAIT_TIMEOUT == result)
/* First check instance
*/
pInstance = WDML_GetInstance(idInst);
if (pInstance == NULL)
{
ERR("WaitForSingleObject timed out\n");
return FALSE;
error_code = DMLERR_DLL_NOT_INITIALIZED;
}
if (WAIT_FAILED == result)
else
{
ERR("WaitForSingleObject failed - error %li\n", GetLastError());
return FALSE;
error_code = pInstance->lastError;
pInstance->lastError = 0;
}
/* TRACE("Handle Mutex created/reserved\n"); */
return TRUE;
LeaveCriticalSection(&WDML_CritSect);
return error_code;
}
/******************************************************************************
* WDML_ReserveAtom
/* ================================================================
*
* Routine to make an extra Add on an atom to reserve it a bit longer
*/
* String management
*
* ================================================================ */
void WDML_ReserveAtom(WDML_INSTANCE* thisInstance, HSZ hsz)
/******************************************************************
* WDML_FindNode
*
*
*/
static HSZNode* WDML_FindNode(WDML_INSTANCE* pInstance, HSZ hsz)
{
if (thisInstance->unicode)
HSZNode* pNode;
if (pInstance == NULL) return NULL;
for (pNode = pInstance->nodeList; pNode != NULL; pNode = pNode->next)
{
WCHAR SNameBuffer[MAX_BUFFER_LEN];
GlobalGetAtomNameW(hsz, SNameBuffer, MAX_BUFFER_LEN);
GlobalAddAtomW(SNameBuffer);
} else {
CHAR SNameBuffer[MAX_BUFFER_LEN];
GlobalGetAtomNameA(hsz, SNameBuffer, MAX_BUFFER_LEN);
GlobalAddAtomA(SNameBuffer);
if (pNode->hsz == hsz) break;
}
if (!pNode) WARN("HSZ 0x%x not found\n", hsz);
return pNode;
}
/******************************************************************************
* WDML_ReleaseAtom
/******************************************************************
* WDML_MakeAtomFromHsz
*
* Routine to make a delete on an atom to release it a bit sooner
* Creates a global atom from an existing HSZ
* Generally used before sending an HSZ as an atom to a remote app
*/
void WDML_ReleaseAtom(WDML_INSTANCE* thisInstance, HSZ hsz)
ATOM WDML_MakeAtomFromHsz(HSZ hsz)
{
GlobalDeleteAtom(hsz);
}
WCHAR nameBuffer[MAX_BUFFER_LEN];
if (GetAtomNameW((ATOM)hsz, nameBuffer, MAX_BUFFER_LEN))
return GlobalAddAtomW(nameBuffer);
WARN("HSZ 0x%xnot found\n", hsz);
return 0;
}
/*****************************************************************
* DdeQueryStringA [USER32.@]
/******************************************************************
* WDML_MakeHszFromAtom
*
* Creates a HSZ from an existing global atom
* Generally used while receiving a global atom and transforming it
* into an HSZ
*/
DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
HSZ WDML_MakeHszFromAtom(WDML_INSTANCE* pInstance, ATOM atom)
{
DWORD ret = 0;
CHAR pString[MAX_BUFFER_LEN];
WDML_INSTANCE* thisInstance;
TRACE("(%ld, 0x%x, %p, %ld, %d): partial stub\n",
idInst, hsz, psz, cchMax, iCodePage);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! */
/* needs something for DdeGetLAstError even if the manual doesn't say so */
return FALSE;
}
if (!WDML_WaitForMutex(handle_mutex))
WCHAR nameBuffer[MAX_BUFFER_LEN];
GlobalGetAtomNameW(atom, nameBuffer, MAX_BUFFER_LEN);
return DdeCreateStringHandleW(pInstance->instanceID, nameBuffer, CP_WINUNICODE);
}
/******************************************************************
* WDML_IncHSZ
*
*
*/
BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
{
HSZNode* pNode;
pNode = WDML_FindNode(pInstance, hsz);
if (!pNode) return FALSE;
pNode->refCount++;
return TRUE;
}
/******************************************************************************
* WDML_DecHSZ (INTERNAL)
*
* Decrease the ref count of an HSZ. If it reaches 0, the node is removed from the list
* of HSZ nodes
* Returns -1 is the HSZ isn't found, otherwise it's the current (after --) of the ref count
*/
BOOL WDML_DecHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
{
HSZNode* pPrev = NULL;
HSZNode* pCurrent;
for (pCurrent = pInstance->nodeList; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next)
{
return FALSE;
/* If we found the node we were looking for and its ref count is one,
* we can remove it
*/
if (pCurrent->hsz == hsz)
{
if (--pCurrent->refCount == 0)
{
if (pCurrent == pInstance->nodeList)
{
pInstance->nodeList = pCurrent->next;
}
else
{
pPrev->next = pCurrent->next;
}
HeapFree(GetProcessHeap(), 0, pCurrent);
DeleteAtom(hsz);
}
return TRUE;
}
}
/* First check instance
WARN("HSZ 0x%xnot found\n", hsz);
return FALSE;
}
/******************************************************************************
* WDML_FreeAllHSZ (INTERNAL)
*
* Frees up all the strings still allocated in the list and
* remove all the nodes from the list of HSZ nodes.
*/
void WDML_FreeAllHSZ(WDML_INSTANCE* pInstance)
{
/* Free any strings created in this instance.
*/
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL)
while (pInstance->nodeList != NULL)
{
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return FALSE;
/*
Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/
return FALSE;
DdeFreeStringHandle(pInstance->instanceID, pInstance->nodeList->hsz);
}
if (iCodePage == CP_WINANSI)
}
/******************************************************************************
* InsertHSZNode (INTERNAL)
*
* Insert a node to the head of the list.
*/
static void WDML_InsertHSZNode(WDML_INSTANCE* pInstance, HSZ hsz)
{
if (hsz != 0)
{
/* If psz is null, we have to return only the length
* of the string.
HSZNode* pNew = NULL;
/* Create a new node for this HSZ.
*/
if (psz == NULL)
pNew = (HSZNode*)HeapAlloc(GetProcessHeap(), 0, sizeof(HSZNode));
if (pNew != NULL)
{
psz = pString;
cchMax = MAX_BUFFER_LEN;
pNew->hsz = hsz;
pNew->next = pInstance->nodeList;
pNew->refCount = 1;
pInstance->nodeList = pNew;
}
else
{
ERR("Primary HSZ Node allocation failed - out of memory\n");
}
ret = GlobalGetAtomNameA(hsz, (LPSTR)psz, cchMax);
}
}
/******************************************************************
* WDML_QueryString
*
*
*/
static int WDML_QueryString(WDML_INSTANCE* pInstance, HSZ hsz, LPVOID ptr, DWORD cchMax,
int codepage)
{
WCHAR pString[MAX_BUFFER_LEN];
int ret;
/* If psz is null, we have to return only the length
* of the string.
*/
if (ptr == NULL)
{
ptr = pString;
cchMax = MAX_BUFFER_LEN;
}
switch (codepage)
{
case CP_WINANSI:
ret = GetAtomNameA(hsz, ptr, cchMax);
break;
case CP_WINUNICODE:
ret = GetAtomNameW(hsz, ptr, cchMax);
default:
ERR("Unknown code page %d\n", codepage);
ret = 0;
}
return ret;
}
/*****************************************************************
* DdeQueryStringA [USER32.@]
*/
DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
{
DWORD ret = 0;
WDML_INSTANCE* pInstance;
TRACE("(%ld, 0x%x, %p, %ld, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
EnterCriticalSection(&WDML_CritSect);
TRACE("returning pointer\n");
/* First check instance
*/
pInstance = WDML_GetInstance(idInst);
if (pInstance != NULL)
{
if (iCodePage == 0) iCodePage = CP_WINANSI;
ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
}
LeaveCriticalSection(&WDML_CritSect);
TRACE("returning %s\n", debugstr_a(psz));
return ret;
}
......@@ -1017,32 +1029,55 @@ DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT
DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
{
DWORD ret = 0;
WCHAR pString[MAX_BUFFER_LEN];
int factor = 1;
TRACE("(%ld, 0x%x, %p, %ld, %d): partial-stub\n",
DWORD ret = 0;
WDML_INSTANCE* pInstance;
TRACE("(%ld, 0x%x, %p, %ld, %d)\n",
idInst, hsz, psz, cchMax, iCodePage);
if (iCodePage == CP_WINUNICODE)
EnterCriticalSection(&WDML_CritSect);
/* First check instance
*/
pInstance = WDML_GetInstance(idInst);
if (pInstance != NULL)
{
/* 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 = GlobalGetAtomNameW(hsz, (LPWSTR)psz, cchMax) * factor;
if (iCodePage == 0) iCodePage = CP_WINUNICODE;
ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
}
LeaveCriticalSection(&WDML_CritSect);
TRACE("returning %s\n", debugstr_w(psz));
return ret;
}
/******************************************************************
* DML_CreateString
*
*
*/
static HSZ WDML_CreateString(WDML_INSTANCE* pInstance, LPCVOID ptr, int codepage)
{
HSZ hsz;
switch (codepage)
{
case CP_WINANSI:
hsz = AddAtomA(ptr);
TRACE("added atom %s with HSZ 0x%x, \n", debugstr_a(ptr), hsz);
break;
case CP_WINUNICODE:
hsz = AddAtomW(ptr);
TRACE("added atom %s with HSZ 0x%x, \n", debugstr_w(ptr), hsz);
break;
default:
ERR("Unknown code page %d\n", codepage);
return 0;
}
WDML_InsertHSZNode(pInstance, hsz);
return hsz;
}
/*****************************************************************
* DdeCreateStringHandleA [USER32.@]
*
......@@ -1053,126 +1088,53 @@ DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, IN
HSZ WINAPI DdeCreateStringHandleA(DWORD idInst, LPCSTR psz, INT codepage)
{
HSZ hsz = 0;
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
TRACE("(%ld,%p,%d)\n", idInst, psz, codepage);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
return FALSE;
}
if (!WDML_WaitForMutex(handle_mutex))
{
return DMLERR_SYS_ERROR;
}
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL)
{
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return 0;
/*
Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/
return 0;
}
EnterCriticalSection(&WDML_CritSect);
if (codepage == CP_WINANSI)
pInstance = WDML_GetInstance(idInst);
if (pInstance)
{
hsz = GlobalAddAtomA(psz);
/* Save the handle so we know to clean it when
* uninitialize is called.
*/
TRACE("added atom %s with HSZ 0x%x, \n",debugstr_a(psz),hsz);
WDML_InsertHSZNode(thisInstance, hsz);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE))
{
thisInstance->lastError = DMLERR_SYS_ERROR;
return 0;
}
TRACE("Returning pointer\n");
return hsz;
if (codepage == 0) codepage = CP_WINANSI;
hsz = WDML_CreateString(pInstance, psz, codepage);
}
else
{
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
}
TRACE("Returning error\n");
return 0;
LeaveCriticalSection(&WDML_CritSect);
return hsz;
}
/******************************************************************************
* DdeCreateStringHandleW [USER32.@] Creates handle to identify string
*
* PARAMS
* idInst [I] Instance identifier
* psz [I] Pointer to string
* codepage [I] Code page identifier
* RETURNS
* Success: String handle
* Failure: 0
*/
HSZ WINAPI DdeCreateStringHandleW(
DWORD idInst, /* [in] Instance identifier */
LPCWSTR psz, /* [in] Pointer to string */
INT codepage) /* [in] Code page identifier */
HSZ WINAPI DdeCreateStringHandleW(DWORD idInst, LPCWSTR psz, INT codepage)
{
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
HSZ hsz = 0;
TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
return FALSE;
}
if (!WDML_WaitForMutex(handle_mutex))
{
return DMLERR_SYS_ERROR;
}
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL)
{
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return 0;
/*
Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/
return 0;
}
TRACE("(%ld,%p,%d)\n", idInst, psz, codepage);
FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
EnterCriticalSection(&WDML_CritSect);
if (codepage == CP_WINUNICODE)
pInstance = WDML_GetInstance(idInst);
if (pInstance)
{
/*
* Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
*/
hsz = GlobalAddAtomW(psz);
/* Save the handle so we know to clean it when
* uninitialize is called.
*/
WDML_InsertHSZNode(thisInstance, hsz);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE))
{
thisInstance->lastError = DMLERR_SYS_ERROR;
return 0;
}
TRACE("Returning pointer\n");
return hsz;
if (codepage == 0) codepage = CP_WINUNICODE;
hsz = WDML_CreateString(pInstance, psz, codepage);
}
else
{
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
}
TRACE("Returning error\n");
return 0;
LeaveCriticalSection(&WDML_CritSect);
return hsz;
}
/*****************************************************************
......@@ -1182,45 +1144,22 @@ HSZ WINAPI DdeCreateStringHandleW(
*/
BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz)
{
WDML_INSTANCE* thisInstance;
HSZ hsz2;
TRACE("(%ld,%d): \n",idInst,hsz);
WDML_INSTANCE* pInstance;
BOOL ret = FALSE;
TRACE("(%ld,0x%x): \n", idInst, hsz);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
return TRUE;
}
if (!WDML_WaitForMutex(handle_mutex))
{
return DMLERR_SYS_ERROR;
}
EnterCriticalSection(&WDML_CritSect);
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if ((thisInstance == NULL) || (thisInstance->nodeList == NULL))
{
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return TRUE;
/* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
return TRUE;
}
/* Remove the node associated with this HSZ.
*/
hsz2 = thisInstance->nodeList->hsz2; /* save this value first */
WDML_RemoveHSZNode(thisInstance, hsz);
/* Free the string associated with this HSZ.
*/
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
if (hsz2 != 0)
{
GlobalDeleteAtom(hsz2);
}
return GlobalDeleteAtom(hsz) ? 0 : hsz;
pInstance = WDML_GetInstance(idInst);
if (pInstance)
ret = WDML_DecHSZ(pInstance, hsz);
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/*****************************************************************
......@@ -1231,38 +1170,90 @@ BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz)
*/
BOOL WINAPI DdeKeepStringHandle(DWORD idInst, HSZ hsz)
{
WDML_INSTANCE* pInstance;
BOOL ret = FALSE;
TRACE("(%ld,0x%x): \n", idInst, hsz);
WDML_INSTANCE* thisInstance;
EnterCriticalSection(&WDML_CritSect);
TRACE("(%ld,%d): \n",idInst,hsz);
/* First check instance
*/
pInstance = WDML_GetInstance(idInst);
if (pInstance)
ret = WDML_IncHSZ(pInstance, hsz);
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/*****************************************************************
* DdeCmpStringHandles (USER32.@)
*
* 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 DdeCmpStringHandles(HSZ hsz1, HSZ hsz2)
{
WCHAR psz1[MAX_BUFFER_LEN];
WCHAR psz2[MAX_BUFFER_LEN];
int ret = 0;
int ret1, ret2;
if (WDML_MaxInstanceID == 0)
ret1 = GetAtomNameW(hsz1, psz1, MAX_BUFFER_LEN);
ret2 = GetAtomNameW(hsz2, psz2, MAX_BUFFER_LEN);
TRACE("(%x<%s> %x<%s>);\n", hsz1, debugstr_w(psz1), hsz2, debugstr_w(psz2));
/* Make sure we found both strings. */
if (ret1 == 0 && ret2 == 0)
{
/* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
return FALSE;
/* If both are not found, return both "zero strings". */
ret = 0;
}
if (!WDML_WaitForMutex(handle_mutex))
else if (ret1 == 0)
{
return FALSE;
/* If hsz1 is a not found, return hsz1 is "zero string". */
ret = -1;
}
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if ((thisInstance == NULL) || (thisInstance->nodeList == NULL))
else if (ret2 == 0)
{
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return FALSE;
/* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
return FALSE;
return FALSE;
/* If hsz2 is a not found, return hsz2 is "zero string". */
ret = 1;
}
WDML_ReserveAtom(thisInstance, hsz);
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return TRUE;
else
{
/* Compare the two strings we got (case insensitive). */
ret = lstrcmpiW(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;
}
/* ================================================================
*
* Data handle management
*
* ================================================================ */
/*****************************************************************
* DdeCreateDataHandle (USER32.@)
*/
......@@ -1330,57 +1321,20 @@ HDDEDATA WINAPI DdeAddData(HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff)
return hData;
}
/*****************************************************************
* DdeSetUserHandle (USER32.@)
*/
BOOL WINAPI DdeSetUserHandle(HCONV hConv, DWORD id, DWORD hUser)
{
WDML_CONV* pConv;
BOOL ret = TRUE;
WDML_WaitForMutex(handle_mutex);
pConv = WDML_GetConv(hConv);
if (pConv == NULL)
{
ret = FALSE;
goto theError;
}
if (id == QID_SYNC)
{
pConv->hUser = hUser;
}
else
{
WDML_XACT* pXAct;
pXAct = WDML_FindTransaction(pConv, id);
if (pXAct)
{
pXAct->hUser = hUser;
}
else
{
pConv->thisInstance->lastError = DMLERR_UNFOUND_QUEUE_ID;
ret = FALSE;
}
}
theError:
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return ret;
}
/******************************************************************************
* DdeGetData [USER32.@] Copies data from DDE object to local buffer
*
*
* PARAMS
* hData [I] Handle to DDE object
* pDst [I] Pointer to destination buffer
* cbMax [I] Amount of data to copy
* cbOff [I] Offset to beginning of data
*
* RETURNS
* Size of memory object associated with handle
*/
DWORD WINAPI DdeGetData(
HDDEDATA hData, /* [in] Handle to DDE object */
LPBYTE pDst, /* [in] Pointer to destination buffer */
DWORD cbMax, /* [in] Amount of data to copy */
DWORD cbOff) /* [in] Offset to beginning of data */
DWORD WINAPI DdeGetData(HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff)
{
DWORD dwSize, dwRet;
LPBYTE pByte;
......@@ -1475,247 +1429,64 @@ BOOL WINAPI DdeFreeDataHandle(HDDEDATA hData)
* 0 16 bit fields for options (release, ackreq, response...)
* 2 16 clipboard format
* 4 ? data to be used
*/
HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem)
{
DDEDATA* pDd;
if (hMem)
{
pDd = GlobalLock(hMem);
if (pDd)
{
return DdeCreateDataHandle(0, pDd->Value,
GlobalSize(hMem) - (sizeof(DDEDATA) - 1),
0, 0, pDd->cfFormat, 0);
}
}
return 0;
}
HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease,
BOOL fDeferUpd, BOOL fAckReq)
{
DDE_DATAHANDLE_HEAD* pDdh;
DWORD dwSize;
HGLOBAL hMem = 0;
dwSize = GlobalSize(hDdeData) - sizeof(DDE_DATAHANDLE_HEAD);
pDdh = (DDE_DATAHANDLE_HEAD*)GlobalLock(hDdeData);
if (dwSize && pDdh)
{
hMem = GlobalAlloc(sizeof(DDEDATA) - 1 + dwSize,
GMEM_MOVEABLE | GMEM_DDESHARE);
if (hMem)
{
DDEDATA* ddeData;
ddeData = GlobalLock(hMem);
if (ddeData)
{
ddeData->fResponse = fResponse;
ddeData->fRelease = fRelease;
ddeData->reserved /*fDeferUpd*/ = fDeferUpd;
ddeData->fAckReq = fAckReq;
ddeData->cfFormat = pDdh->cfFormat;
memcpy(ddeData->Value, pDdh + 1, dwSize);
GlobalUnlock(hMem);
}
}
GlobalUnlock(hDdeData);
}
return hMem;
}
/*****************************************************************
* DdeEnableCallback (USER32.@)
*/
BOOL WINAPI DdeEnableCallback(DWORD idInst, HCONV hConv, UINT wCmd)
{
FIXME("(%ld, 0x%x, %d) stub\n", idInst, hConv, wCmd);
return 0;
}
/******************************************************************************
* DdeGetLastError [USER32.@] Gets most recent error code
*
* PARAMS
* idInst [I] Instance identifier
*
* RETURNS
* Last error code
*/
UINT WINAPI DdeGetLastError(DWORD idInst)
{
DWORD error_code;
WDML_INSTANCE* thisInstance;
FIXME("(%ld): error reporting is weakly implemented\n",idInst);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now ! */
return DMLERR_DLL_NOT_INITIALIZED;
}
if (!WDML_WaitForMutex(handle_mutex))
{
return DMLERR_SYS_ERROR;
}
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL)
{
error_code = DMLERR_DLL_NOT_INITIALIZED;
}
else
{
error_code = thisInstance->lastError;
thisInstance->lastError = 0;
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return error_code;
}
/*****************************************************************
* DdeCmpStringHandles (USER32.@)
*
* 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 DdeCmpStringHandles(HSZ hsz1, HSZ hsz2)
{
CHAR psz1[MAX_BUFFER_LEN];
CHAR psz2[MAX_BUFFER_LEN];
int ret = 0;
int ret1, ret2;
ret1 = GlobalGetAtomNameA(hsz1, psz1, MAX_BUFFER_LEN);
ret2 = GlobalGetAtomNameA(hsz2, psz2, MAX_BUFFER_LEN);
TRACE("(%04lx<%s> %04lx<%s>);\n", (DWORD)hsz1, psz1, (DWORD)hsz2, psz2);
/* 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;
}
*/
HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem, WINE_DDEHEAD* p)
{
DDEDATA* pDd;
HDDEDATA ret = 0;
if (hMem)
{
pDd = GlobalLock(hMem);
if (pDd)
{
if (p) memcpy(p, pDd, sizeof(WINE_DDEHEAD));
ret = DdeCreateDataHandle(0, pDd->Value,
GlobalSize(hMem) - sizeof(WINE_DDEHEAD),
0, 0, pDd->cfFormat, 0);
GlobalUnlock(hMem);
}
}
return ret;
}
/******************************************************************
* DdeQueryConvInfo (USER32.@)
* WDML_DataHandle2Global
*
*
*/
UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, LPCONVINFO lpConvInfo)
HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease,
BOOL fDeferUpd, BOOL fAckReq)
{
UINT ret = lpConvInfo->cb;
CONVINFO ci;
WDML_CONV* pConv;
FIXME("semi-stub.\n");
WDML_WaitForMutex(handle_mutex);
pConv = WDML_GetConv(hConv);
if (pConv == NULL)
{
WDML_ReleaseMutex(handle_mutex, "hande_mutex", FALSE);
return 0;
}
ci.hConvPartner = 0; /* FIXME */
ci.hszSvcPartner = pConv->hszService;
ci.hszServiceReq = pConv->hszService; /* FIXME: they shouldn't be the same, should they ? */
ci.hszTopic = pConv->hszTopic;
ci.wStatus = ST_CLIENT /* FIXME */ | ST_CONNECTED;
ci.wConvst = 0; /* FIXME */
ci.wLastError = 0; /* FIXME: note it's not the instance last error */
ci.hConvList = 0;
ci.ConvCtxt = pConv->convContext;
if (ci.wStatus & ST_CLIENT)
{
ci.hwnd = pConv->hwndClient;
ci.hwndPartner = pConv->hwndServer;
}
else
{
ci.hwnd = pConv->hwndServer;
ci.hwndPartner = pConv->hwndClient;
}
if (id == QID_SYNC)
{
ci.hUser = pConv->hUser;
ci.hszItem = 0;
ci.wFmt = 0;
ci.wType = 0;
}
else
DDE_DATAHANDLE_HEAD* pDdh;
DWORD dwSize;
HGLOBAL hMem = 0;
dwSize = GlobalSize(hDdeData) - sizeof(DDE_DATAHANDLE_HEAD);
pDdh = (DDE_DATAHANDLE_HEAD*)GlobalLock(hDdeData);
if (dwSize && pDdh)
{
WDML_XACT* pXAct;
pXAct = WDML_FindTransaction(pConv, id);
if (pXAct)
{
ci.hUser = pXAct->hUser;
ci.hszItem = 0; /* FIXME */
ci.wFmt = 0; /* FIXME */
ci.wType = 0; /* FIXME */
}
else
{
ret = 0;
pConv->thisInstance->lastError = DMLERR_UNFOUND_QUEUE_ID;
}
hMem = GlobalAlloc(sizeof(WINE_DDEHEAD) + dwSize, GMEM_MOVEABLE | GMEM_DDESHARE);
if (hMem)
{
WINE_DDEHEAD* wdh;
wdh = GlobalLock(hMem);
if (wdh)
{
wdh->fResponse = fResponse;
wdh->fRelease = fRelease;
wdh->fDeferUpd = fDeferUpd;
wdh->fAckReq = fAckReq;
wdh->cfFormat = pDdh->cfFormat;
memcpy(wdh + 1, pDdh + 1, dwSize);
GlobalUnlock(hMem);
}
}
GlobalUnlock(hDdeData);
}
WDML_ReleaseMutex(handle_mutex, "hande_mutex", FALSE);
memcpy(lpConvInfo, &ci, min(lpConvInfo->cb, sizeof(ci)));
return ret;
return hMem;
}
/* ================================================================
......@@ -1729,19 +1500,28 @@ UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, LPCONVINFO lpConvInfo)
*
*
*/
WDML_SERVER* WDML_AddServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic)
WDML_SERVER* WDML_AddServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic)
{
WDML_SERVER* pServer;
WDML_SERVER* pServer;
char buf1[256];
char buf2[256];
pServer = (WDML_SERVER*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_SERVER));
if (pServer == NULL) return NULL;
pServer->hszService = hszService;
pServer->hszTopic = 0;
WDML_IncHSZ(pInstance, pServer->hszService = hszService);
DdeQueryStringA(pInstance->instanceID, hszService, buf1, sizeof(buf1), CP_WINANSI);
snprintf(buf2, sizeof(buf2), "%s(0x%08lx)", buf1, GetCurrentProcessId());
pServer->hszServiceSpec = DdeCreateStringHandleA(pInstance->instanceID, buf2, CP_WINANSI);
pServer->atomService = WDML_MakeAtomFromHsz(pServer->hszService);
pServer->atomServiceSpec = WDML_MakeAtomFromHsz(pServer->hszServiceSpec);
pServer->filterOn = TRUE;
pServer->next = thisInstance->servers;
thisInstance->servers = pServer;
pServer->next = pInstance->servers;
pInstance->servers = pServer;
return pServer;
}
......@@ -1750,34 +1530,54 @@ WDML_SERVER* WDML_AddServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hsz
*
*
*/
void WDML_RemoveServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic)
void WDML_RemoveServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic)
{
WDML_SERVER* pPrev = NULL;
WDML_SERVER* pCurrent = NULL;
pCurrent = thisInstance->servers;
WDML_SERVER* pPrev = NULL;
WDML_SERVER* pServer = NULL;
WDML_CONV* pConv;
WDML_CONV* pConvNext;
pServer = pInstance->servers;
while (pCurrent != NULL)
while (pServer != NULL)
{
if (DdeCmpStringHandles(pCurrent->hszService, hszService) == 0)
if (DdeCmpStringHandles(pServer->hszService, hszService) == 0)
{
if (pCurrent == thisInstance->servers)
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_UNREGISTER,
pServer->atomService, pServer->atomServiceSpec);
/* terminate all conversations for given topic */
for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConvNext)
{
pConvNext = pConv->next;
if (DdeCmpStringHandles(pConv->hszService, hszService) == 0)
{
WDML_RemoveConv(pConv, WDML_SERVER_SIDE);
/* don't care about return code (whether client window is present or not) */
PostMessageA(pConv->hwndClient, WM_DDE_TERMINATE, (WPARAM)pConv->hwndServer, 0L);
}
}
if (pServer == pInstance->servers)
{
thisInstance->servers = pCurrent->next;
pInstance->servers = pServer->next;
}
else
{
pPrev->next = pCurrent->next;
pPrev->next = pServer->next;
}
DestroyWindow(pCurrent->hwndServer);
HeapFree(GetProcessHeap(), 0, pCurrent);
DestroyWindow(pServer->hwndServer);
WDML_DecHSZ(pInstance, pServer->hszServiceSpec);
WDML_DecHSZ(pInstance, pServer->hszService);
GlobalDeleteAtom(pServer->atomService);
GlobalDeleteAtom(pServer->atomServiceSpec);
HeapFree(GetProcessHeap(), 0, pServer);
break;
}
pPrev = pCurrent;
pCurrent = pCurrent->next;
pPrev = pServer;
pServer = pServer->next;
}
}
......@@ -1787,13 +1587,12 @@ void WDML_RemoveServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic
* generic routine to return a pointer to the relevant ServiceNode
* for a given service name, or NULL if the entry does not exist
*
* ASSUMES the mutex protecting the handle entry list is reserved before calling
*/
WDML_SERVER* WDML_FindServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic)
WDML_SERVER* WDML_FindServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic)
{
WDML_SERVER* pServer;
for (pServer = thisInstance->servers; pServer != NULL; pServer = pServer->next)
for (pServer = pInstance->servers; pServer != NULL; pServer = pServer->next)
{
if (hszService == pServer->hszService)
{
......@@ -1815,7 +1614,7 @@ WDML_SERVER* WDML_FindServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hs
*
*
*/
WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
WDML_CONV* WDML_AddConv(WDML_INSTANCE* pInstance, WDML_SIDE side,
HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer)
{
WDML_CONV* pConv;
......@@ -1823,17 +1622,25 @@ WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
/* no converstation yet, add it */
pConv = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_CONV));
if (!pConv) return NULL;
pConv->thisInstance = thisInstance;
pConv->hszService = hszService;
pConv->hszTopic = hszTopic;
pConv->instance = pInstance;
WDML_IncHSZ(pInstance, pConv->hszService = hszService);
WDML_IncHSZ(pInstance, pConv->hszTopic = hszTopic);
pConv->hwndServer = hwndServer;
pConv->hwndClient = hwndClient;
pConv->transactions = NULL;
pConv->hUser = 0;
pConv->wStatus = (side == WDML_CLIENT_SIDE) ? ST_CLIENT : 0L;
/* check if both side of the conversation are of the same instance */
if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) &&
WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer))
{
pConv->wStatus |= ST_ISSELF;
}
pConv->wConvst = XST_NULL;
pConv->next = thisInstance->convs[side];
thisInstance->convs[side] = pConv;
pConv->next = pInstance->convs[side];
pInstance->convs[side] = pConv;
return pConv;
}
......@@ -1843,12 +1650,12 @@ WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
*
*
*/
WDML_CONV* WDML_FindConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
WDML_CONV* WDML_FindConv(WDML_INSTANCE* pInstance, WDML_SIDE side,
HSZ hszService, HSZ hszTopic)
{
WDML_CONV* pCurrent = NULL;
for (pCurrent = thisInstance->convs[side]; pCurrent != NULL; pCurrent = pCurrent->next)
for (pCurrent = pInstance->convs[side]; pCurrent != NULL; pCurrent = pCurrent->next)
{
if (DdeCmpStringHandles(pCurrent->hszService, hszService) == 0 &&
DdeCmpStringHandles(pCurrent->hszTopic, hszTopic) == 0)
......@@ -1865,21 +1672,48 @@ WDML_CONV* WDML_FindConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
*
*
*/
void WDML_RemoveConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, HCONV hConv)
void WDML_RemoveConv(WDML_CONV* pRef, WDML_SIDE side)
{
WDML_CONV* pPrev = NULL;
WDML_CONV* pRef = WDML_GetConv(hConv);
WDML_CONV* pCurrent = NULL;
WDML_CONV* pPrev = NULL;
WDML_CONV* pCurrent;
WDML_XACT* pXAct;
WDML_XACT* pXActNext;
HWND hWnd;
if (!pRef)
return;
for (pCurrent = thisInstance->convs[side]; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next)
/* remove any pending transaction */
for (pXAct = pRef->transactions; pXAct != NULL; pXAct = pXActNext)
{
pXActNext = pXAct->next;
WDML_FreeTransaction(pRef->instance, pXAct, TRUE);
}
WDML_RemoveAllLinks(pRef->instance, pRef, side);
/* FIXME: should we keep the window around ? it seems so (at least on client side
* to let QueryConvInfo work after conv termination, but also to implement
* DdeReconnect...
*/
/* destroy conversation window, but first remove pConv from hWnd.
* this would help the wndProc do appropriate handling upon a WM_DESTROY message
*/
hWnd = (side == WDML_CLIENT_SIDE) ? pRef->hwndClient : pRef->hwndServer;
SetWindowLongA(hWnd, GWL_WDML_CONVERSATION, 0);
DestroyWindow((side == WDML_CLIENT_SIDE) ? pRef->hwndClient : pRef->hwndServer);
WDML_DecHSZ(pRef->instance, pRef->hszService);
WDML_DecHSZ(pRef->instance, pRef->hszTopic);
for (pCurrent = pRef->instance->convs[side]; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next)
{
if (pCurrent == pRef)
{
if (pCurrent == thisInstance->convs[side])
if (pCurrent == pRef->instance->convs[side])
{
thisInstance->convs[side] = pCurrent->next;
pRef->instance->convs[side] = pCurrent->next;
}
else
{
......@@ -1892,15 +1726,239 @@ void WDML_RemoveConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, HCONV hConv)
}
}
/*****************************************************************
* DdeEnableCallback (USER32.@)
*/
BOOL WINAPI DdeEnableCallback(DWORD idInst, HCONV hConv, UINT wCmd)
{
FIXME("(%ld, 0x%x, %d) stub\n", idInst, hConv, wCmd);
return 0;
}
/******************************************************************
* WDML_GetConv
*
*
*/
WDML_CONV* WDML_GetConv(HCONV hConv)
WDML_CONV* WDML_GetConv(HCONV hConv, BOOL checkConnected)
{
WDML_CONV* pConv = (WDML_CONV*)hConv;
/* FIXME: should do better checking */
return (WDML_CONV*)hConv;
if (checkConnected && !(pConv->wStatus & ST_CONNECTED))
{
FIXME("found conv but ain't connected\n");
return NULL;
}
if (GetCurrentThreadId() != pConv->instance->threadID)
{
FIXME("wrong thread ID\n");
return NULL;
}
return pConv;
}
/******************************************************************
* WDML_GetConvFromWnd
*
*
*/
WDML_CONV* WDML_GetConvFromWnd(HWND hWnd)
{
return (WDML_CONV*)GetWindowLongA(hWnd, GWL_WDML_CONVERSATION);
}
/******************************************************************
* WDML_PostAck
*
*
*/
LPARAM WDML_PostAck(WDML_CONV* pConv, WDML_SIDE side, WORD appRetCode,
BOOL fBusy, BOOL fAck, ATOM atom, LPARAM lParam, UINT oldMsg)
{
DDEACK ddeAck;
HWND from, to;
if (side == WDML_SERVER_SIDE)
{
from = pConv->hwndServer;
to = pConv->hwndClient;
}
else
{
to = pConv->hwndServer;
from = pConv->hwndClient;
}
ddeAck.bAppReturnCode = appRetCode;
ddeAck.reserved = 0;
ddeAck.fBusy = fBusy;
ddeAck.fAck = fAck;
TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative");
if (lParam) {
PostMessageA(to, WM_DDE_ACK, (WPARAM)from,
ReuseDDElParam(lParam, oldMsg, WM_DDE_ACK, *(WORD*)&ddeAck, atom));
}
else
{
lParam = PackDDElParam(WM_DDE_ACK, *(WORD*)&ddeAck, atom);
PostMessageA(to, WM_DDE_ACK, (WPARAM)from, lParam);
}
return lParam;
}
/*****************************************************************
* DdeSetUserHandle (USER32.@)
*/
BOOL WINAPI DdeSetUserHandle(HCONV hConv, DWORD id, DWORD hUser)
{
WDML_CONV* pConv;
BOOL ret = TRUE;
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv == NULL)
{
ret = FALSE;
goto theError;
}
if (id == QID_SYNC)
{
pConv->hUser = hUser;
}
else
{
WDML_XACT* pXAct;
pXAct = WDML_FindTransaction(pConv, id);
if (pXAct)
{
pXAct->hUser = hUser;
}
else
{
pConv->instance->lastError = DMLERR_UNFOUND_QUEUE_ID;
ret = FALSE;
}
}
theError:
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/******************************************************************
* WDML_GetLocalConvInfo
*
*
*/
static BOOL WDML_GetLocalConvInfo(WDML_CONV* pConv, CONVINFO* ci, DWORD id)
{
BOOL ret = TRUE;
WDML_LINK* pLink;
WDML_SIDE side;
ci->hConvPartner = (pConv->wStatus & ST_ISLOCAL) ? (HCONV)((DWORD)pConv | 1) : 0;
ci->hszSvcPartner = pConv->hszService;
ci->hszServiceReq = pConv->hszService; /* FIXME: they shouldn't be the same, should they ? */
ci->hszTopic = pConv->hszTopic;
ci->wStatus = pConv->wStatus;
side = (pConv->wStatus & ST_CLIENT) ? WDML_CLIENT_SIDE : WDML_SERVER_SIDE;
for (pLink = pConv->instance->links[side]; pLink != NULL; pLink = pLink->next)
{
if (pLink->hConv == (HWND)pConv)
{
ci->wStatus |= ST_ADVISE;
break;
}
}
/* FIXME: non handled status flags:
ST_BLOCKED
ST_BLOCKNEXT
ST_INLIST
*/
ci->wConvst = pConv->wConvst; /* FIXME */
ci->wLastError = 0; /* FIXME: note it's not the instance last error */
ci->hConvList = 0;
ci->ConvCtxt = pConv->convContext;
if (ci->wStatus & ST_CLIENT)
{
ci->hwnd = pConv->hwndClient;
ci->hwndPartner = pConv->hwndServer;
}
else
{
ci->hwnd = pConv->hwndServer;
ci->hwndPartner = pConv->hwndClient;
}
if (id == QID_SYNC)
{
ci->hUser = pConv->hUser;
ci->hszItem = 0;
ci->wFmt = 0;
ci->wType = 0;
}
else
{
WDML_XACT* pXAct;
pXAct = WDML_FindTransaction(pConv, id);
if (pXAct)
{
ci->hUser = pXAct->hUser;
ci->hszItem = pXAct->hszItem;
ci->wFmt = pXAct->wFmt;
ci->wType = pXAct->wType;
}
else
{
ret = 0;
pConv->instance->lastError = DMLERR_UNFOUND_QUEUE_ID;
}
}
return ret;
}
/******************************************************************
* DdeQueryConvInfo (USER32.@)
*
*/
UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, LPCONVINFO lpConvInfo)
{
UINT ret = lpConvInfo->cb;
CONVINFO ci;
WDML_CONV* pConv;
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv != NULL && !WDML_GetLocalConvInfo(pConv, &ci, id))
{
ret = 0;
}
else if (hConv & 1)
{
pConv = WDML_GetConv(hConv & ~1, FALSE);
if (pConv != NULL)
{
FIXME("Request on remote conversation information is not implemented yet\n");
ret = 0;
}
}
LeaveCriticalSection(&WDML_CritSect);
if (ret != 0)
memcpy(lpConvInfo, &ci, min(lpConvInfo->cb, sizeof(ci)));
return ret;
}
/* ================================================================
......@@ -1914,13 +1972,11 @@ WDML_CONV* WDML_GetConv(HCONV hConv)
*
*
*/
void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
void WDML_AddLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
UINT wType, HSZ hszItem, UINT wFmt)
{
WDML_LINK* pLink;
TRACE("AddDdeLink was called...\n");
pLink = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_LINK));
if (pLink == NULL)
{
......@@ -1930,11 +1986,11 @@ void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
pLink->hConv = hConv;
pLink->transactionType = wType;
pLink->hszItem = hszItem;
WDML_IncHSZ(pInstance, pLink->hszItem = hszItem);
pLink->uFmt = wFmt;
pLink->hDdeData = 0;
pLink->next = thisInstance->links[side];
thisInstance->links[side] = pLink;
pLink->next = pInstance->links[side];
pInstance->links[side] = pLink;
}
/******************************************************************
......@@ -1942,13 +1998,13 @@ void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
*
*
*/
void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
void WDML_RemoveLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
HSZ hszItem, UINT uFmt)
{
WDML_LINK* pPrev = NULL;
WDML_LINK* pCurrent = NULL;
pCurrent = thisInstance->links[side];
pCurrent = pInstance->links[side];
while (pCurrent != NULL)
{
......@@ -1956,9 +2012,9 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
pCurrent->uFmt == uFmt)
{
if (pCurrent == thisInstance->links[side])
if (pCurrent == pInstance->links[side])
{
thisInstance->links[side] = pCurrent->next;
pInstance->links[side] = pCurrent->next;
}
else
{
......@@ -1969,7 +2025,8 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
{
DdeFreeDataHandle(pCurrent->hDdeData);
}
WDML_DecHSZ(pInstance, pCurrent->hszItem);
HeapFree(GetProcessHeap(), 0, pCurrent);
break;
}
......@@ -1988,21 +2045,21 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
*
*
*/
void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side)
void WDML_RemoveAllLinks(WDML_INSTANCE* pInstance, WDML_CONV* pConv, WDML_SIDE side)
{
WDML_LINK* pPrev = NULL;
WDML_LINK* pCurrent = NULL;
WDML_LINK* pNext = NULL;
pCurrent = thisInstance->links[side];
pCurrent = pInstance->links[side];
while (pCurrent != NULL)
{
if (pCurrent->hConv == hConv)
if (pCurrent->hConv == (HCONV)pConv)
{
if (pCurrent == thisInstance->links[side])
if (pCurrent == pInstance->links[side])
{
thisInstance->links[side] = pCurrent->next;
pInstance->links[side] = pCurrent->next;
pNext = pCurrent->next;
}
else
......@@ -2015,6 +2072,7 @@ void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE sid
{
DdeFreeDataHandle(pCurrent->hDdeData);
}
WDML_DecHSZ(pInstance, pCurrent->hszItem);
HeapFree(GetProcessHeap(), 0, pCurrent);
pCurrent = NULL;
......@@ -2037,15 +2095,14 @@ void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE sid
*
*
*/
WDML_LINK* WDML_FindLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
WDML_LINK* WDML_FindLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
HSZ hszItem, UINT uFmt)
{
WDML_LINK* pCurrent = NULL;
for (pCurrent = thisInstance->links[side]; pCurrent != NULL; pCurrent = pCurrent->next)
for (pCurrent = pInstance->links[side]; pCurrent != NULL; pCurrent = pCurrent->next)
{
/* we don't need to check for transaction type as
it can be altered */
/* we don't need to check for transaction type as it can be altered */
if (pCurrent->hConv == hConv &&
DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
......@@ -2070,7 +2127,8 @@ WDML_LINK* WDML_FindLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE si
*
* Alloc a transaction structure for handling the message ddeMsg
*/
WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg)
WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* pInstance, UINT ddeMsg,
UINT wFmt, HSZ hszItem)
{
WDML_XACT* pXAct;
static WORD tid = 1; /* FIXME: wrap around */
......@@ -2078,7 +2136,7 @@ WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg)
pXAct = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_XACT));
if (!pXAct)
{
thisInstance->lastError = DMLERR_MEMORY_ERROR;
pInstance->lastError = DMLERR_MEMORY_ERROR;
return NULL;
}
......@@ -2087,7 +2145,13 @@ WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg)
pXAct->hDdeData = 0;
pXAct->hUser = 0;
pXAct->next = NULL;
pXAct->wType = 0;
pXAct->wFmt = wFmt;
WDML_IncHSZ(pInstance, pXAct->hszItem = hszItem);
pXAct->atom = 0;
pXAct->hMem = 0;
pXAct->lParam = 0;
return pXAct;
}
......@@ -2130,8 +2194,13 @@ BOOL WDML_UnQueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct)
*
*
*/
void WDML_FreeTransaction(WDML_XACT* pXAct)
void WDML_FreeTransaction(WDML_INSTANCE* pInstance, WDML_XACT* pXAct, BOOL doFreePmt)
{
/* free pmt(s) in pXAct too */
if (doFreePmt && pXAct->hMem)
GlobalFree(pXAct->hMem);
WDML_DecHSZ(pInstance, pXAct->hszItem);
HeapFree(GetProcessHeap(), 0, pXAct);
}
......@@ -2153,6 +2222,12 @@ WDML_XACT* WDML_FindTransaction(WDML_CONV* pConv, DWORD tid)
return pXAct;
}
/* ================================================================
*
* Information broadcast across DDEML implementations
*
* ================================================================ */
struct tagWDML_BroadcastPmt
{
LPCSTR clsName;
......
......@@ -23,8 +23,9 @@
DEFAULT_DEBUG_CHANNEL(ddeml);
static const char szServerNameClassA[] = "DdeServerNameAnsi";
static const char szServerConvClassA[] = "DdeServerConvAnsi";
static const char szServerNameClassA[] = "DdeServerNameAnsi";
const char WDML_szServerConvClassA[] = "DdeServerConvAnsi";
const WCHAR WDML_szServerConvClassW[] = {'D','d','e','S','e','r','v','e','r','C','o','n','v','U','n','i','c','o','d','e',0};
static LRESULT CALLBACK WDML_ServerNameProc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK WDML_ServerConvProc(HWND, UINT, WPARAM, LPARAM);
......@@ -32,60 +33,66 @@ static LRESULT CALLBACK WDML_ServerConvProc(HWND, UINT, WPARAM, LPARAM);
/******************************************************************************
* DdePostAdvise [USER32.@] Send transaction to DDE callback function.
*
* PARAMS
* idInst [I] Instance identifier
* hszTopic [I] Handle to topic name string
* hszItem [I] Handle to item name string
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI DdePostAdvise(
DWORD idInst, /* [in] Instance identifier */
HSZ hszTopic, /* [in] Handle to topic name string */
HSZ hszItem) /* [in] Handle to item name string */
BOOL WINAPI DdePostAdvise(DWORD idInst, HSZ hszTopic, HSZ hszItem)
{
WDML_INSTANCE* thisInstance = NULL;
WDML_INSTANCE* pInstance = NULL;
WDML_LINK* pLink = NULL;
HDDEDATA hDdeData = 0, hItemData = 0;
WDML_CONV* pConv = NULL;
CHAR pszTopic[MAX_BUFFER_LEN];
CHAR pszItem[MAX_BUFFER_LEN];
ATOM atom = 0;
UINT count;
TRACE("(%ld,0x%x,0x%x)\n", idInst, hszTopic, hszItem);
TRACE("(%ld,%ld,%ld)\n",idInst,(DWORD)hszTopic,(DWORD)hszItem);
EnterCriticalSection(&WDML_CritSect);
pInstance = WDML_GetInstance(idInst);
if (idInst == 0)
if (pInstance == NULL || pInstance->links == NULL)
{
return FALSE;
goto theError;
}
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL || thisInstance->links == NULL)
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) goto theError;
/* first compute the number of links which will trigger a message */
count = 0;
for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
{
if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0)
{
count++;
}
}
if (count >= CADV_LATEACK)
{
return FALSE;
FIXME("too high value for count\n");
count &= 0xFFFF;
}
GlobalGetAtomNameA(hszTopic, (LPSTR)pszTopic, MAX_BUFFER_LEN);
GlobalGetAtomNameA(hszItem, (LPSTR)pszItem, MAX_BUFFER_LEN);
for (pLink = thisInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
{
if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0)
{
hDdeData = 0;
if (thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId()*/)
{
TRACE("Calling the callback, type=XTYP_ADVREQ, CB=0x%lx, hConv=0x%lx, Topic=%s, Item=%s\n",
(DWORD)thisInstance->callback, (DWORD)pLink->hConv, pszTopic, pszItem);
hDdeData = (thisInstance->callback)(XTYP_ADVREQ,
pLink->uFmt,
pLink->hConv,
hszTopic,
hszItem,
0, 0, 0);
TRACE("Callback was called\n");
hDdeData = WDML_InvokeCallback(pInstance, XTYP_ADVREQ, pLink->uFmt, pLink->hConv,
hszTopic, hszItem, 0, count--, 0);
if (hDdeData == CBR_BLOCK)
{
/* MS doc is not consistent here */
FIXME("CBR_BLOCK returned for ADVREQ\n");
continue;
}
if (hDdeData)
{
if (pLink->transactionType & XTYPF_NODATA)
......@@ -100,21 +107,33 @@ BOOL WINAPI DdePostAdvise(
hItemData = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE);
}
pConv = WDML_GetConv(pLink->hConv);
pConv = WDML_GetConv(pLink->hConv, TRUE);
if (pConv == NULL)
{
/* FIXME: wrong if app owned... */
DdeFreeDataHandle(hDdeData);
goto theError;
}
if (pConv == NULL ||
!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
PackDDElParam(WM_DDE_DATA, (UINT)hItemData, (DWORD)hszItem)))
if (!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
PackDDElParam(WM_DDE_DATA, (UINT)hItemData, atom)))
{
ERR("post message failed\n");
/* FIXME: wrong if app owned... */
DdeFreeDataHandle(hDdeData);
return FALSE;
GlobalFree(hItemData);
goto theError;
}
}
}
}
LeaveCriticalSection(&WDML_CritSect);
return TRUE;
theError:
LeaveCriticalSection(&WDML_CritSect);
if (atom) GlobalDeleteAtom(atom);
return FALSE;
}
......@@ -134,113 +153,64 @@ BOOL WINAPI DdePostAdvise(
HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
{
WDML_SERVER* pServer;
WDML_SERVER* pServerTmp;
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
HDDEDATA hDdeData;
HSZ hsz2nd = 0;
HWND hwndServer;
WNDCLASSEXA wndclass;
hDdeData = (HDDEDATA)NULL;
TRACE("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now !
* needs something for DdeGetLastError */
return 0;
}
TRACE("(%ld,0x%x,0x%x,%d)\n", idInst, hsz1, hsz2, afCmd);
if (!WDML_WaitForMutex(handle_mutex))
{
/* FIXME: setError DMLERR_SYS_ERROR; */
return 0;
}
EnterCriticalSection(&WDML_CritSect);
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if (thisInstance == NULL)
pInstance = WDML_GetInstance(idInst);
if (pInstance == NULL)
{
TRACE("Instance not found as initialised\n");
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
/* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
return FALSE;
goto theError;
}
if (hsz2 != 0L)
{
/* Illegal, reserved parameter
*/
thisInstance->lastError = DMLERR_INVALIDPARAMETER;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
FIXME("Reserved parameter no-zero !!\n");
return FALSE;
pInstance->lastError = DMLERR_INVALIDPARAMETER;
WARN("Reserved parameter no-zero !!\n");
goto theError;
}
if (hsz1 == 0L)
if (hsz1 == 0 && afCmd != DNS_UNREGISTER)
{
/*
* General unregister situation
*/
if (afCmd != DNS_UNREGISTER)
{
/* don't know if we should check this but it makes sense
* why supply REGISTER or filter flags if de-registering all
*/
TRACE("General unregister unexpected flags\n");
thisInstance->lastError = DMLERR_DLL_USAGE;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return FALSE;
}
/* Loop to find all registered service and de-register them
/* don't know if we should check this but it makes sense
* why supply REGISTER or filter flags if de-registering all
*/
if (thisInstance->servers == NULL)
{
/* None to unregister !!
*/
TRACE("General de-register - nothing registered\n");
thisInstance->lastError = DMLERR_DLL_USAGE;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return FALSE;
}
else
{
pServer = thisInstance->servers;
while (pServer != NULL)
{
TRACE("general deregister - iteration\n");
pServerTmp = pServer;
pServer = pServer->next;
WDML_ReleaseAtom(thisInstance, pServerTmp->hszService);
/* finished - release heap space used as work store */
HeapFree(GetProcessHeap(), 0, pServerTmp);
}
thisInstance->servers = NULL;
TRACE("General de-register - finished\n");
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return (HDDEDATA)TRUE;
TRACE("General unregister unexpected flags\n");
pInstance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
TRACE("Specific name action detected\n");
if (afCmd & DNS_REGISTER)
switch (afCmd)
{
/* Register new service name
*/
pServer = WDML_FindServer(thisInstance, hsz1, 0);
case DNS_REGISTER:
pServer = WDML_FindServer(pInstance, hsz1, 0);
if (pServer)
ERR("Trying to register already registered service!\n");
else
{
TRACE("Adding service name\n");
ERR("Trying to register already registered service!\n");
pInstance->lastError = DMLERR_DLL_USAGE;
goto theError;
}
TRACE("Adding service name\n");
WDML_ReserveAtom(thisInstance, hsz1);
WDML_IncHSZ(pInstance, hsz1);
pServer = WDML_AddServer(thisInstance, hsz1, 0);
pServer = WDML_AddServer(pInstance, hsz1, 0);
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_REGISTER, hsz1, hsz2nd);
}
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_REGISTER,
pServer->atomService, pServer->atomServiceSpec);
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
......@@ -257,63 +227,59 @@ HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
RegisterClassExA(&wndclass);
LeaveCriticalSection(&WDML_CritSect);
hwndServer = CreateWindowA(szServerNameClassA, NULL,
WS_POPUP, 0, 0, 0, 0,
0, 0, 0, 0);
SetWindowLongA(hwndServer, 0, (DWORD)thisInstance);
EnterCriticalSection(&WDML_CritSect);
SetWindowLongA(hwndServer, GWL_WDML_INSTANCE, (DWORD)pInstance);
SetWindowLongA(hwndServer, GWL_WDML_SERVER, (DWORD)pServer);
TRACE("Created nameServer=%04x for instance=%08lx\n", hwndServer, idInst);
pServer->hwndServer = hwndServer;
}
if (afCmd & DNS_UNREGISTER)
{
TRACE("Broadcasting WM_DDE_TERMINATE message\n");
SendMessageA(HWND_BROADCAST, WM_DDE_TERMINATE, (WPARAM)NULL,
PackDDElParam(WM_DDE_TERMINATE, (UINT)hsz1, (UINT)hsz2));
WDML_RemoveServer(thisInstance, hsz1, hsz2);
}
if (afCmd & DNS_FILTERON)
{
/* Set filter flags on to hold notifications of connection
*
* test coded this way as this is the default setting
*/
pServer = WDML_FindServer(thisInstance, hsz1, 0);
if (!pServer)
break;
case DNS_UNREGISTER:
if (hsz1 == 0L)
{
/* trying to filter where no service names !!
/* General unregister situation
* terminate all server side pending conversations
*/
thisInstance->lastError = DMLERR_DLL_USAGE;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return FALSE;
}
else
while (pInstance->servers)
WDML_RemoveServer(pInstance, pInstance->servers->hszService, 0);
pInstance->servers = NULL;
TRACE("General de-register - finished\n");
}
else
{
pServer->filterOn = TRUE;
WDML_RemoveServer(pInstance, hsz1, 0L);
}
}
if (afCmd & DNS_FILTEROFF)
{
break;
case DNS_FILTERON:
case DNS_FILTEROFF:
/* Set filter flags on to hold notifications of connection
*/
pServer = WDML_FindServer(thisInstance, hsz1, 0);
pServer = WDML_FindServer(pInstance, hsz1, 0);
if (!pServer)
{
/* trying to filter where no service names !!
*/
thisInstance->lastError = DMLERR_DLL_USAGE;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
return FALSE;
}
pInstance->lastError = DMLERR_DLL_USAGE;
goto theError;
}
else
{
pServer->filterOn = FALSE;
pServer->filterOn = (afCmd == DNS_FILTERON);
}
break;
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
LeaveCriticalSection(&WDML_CritSect);
return (HDDEDATA)TRUE;
theError:
LeaveCriticalSection(&WDML_CritSect);
return FALSE;
}
/******************************************************************
......@@ -321,56 +287,85 @@ HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
*
*
*/
static BOOL WDML_CreateServerConv(WDML_INSTANCE* thisInstance, HWND hwndClient, HWND hwndServerName,
HSZ hszApp, HSZ hszTopic)
static WDML_CONV* WDML_CreateServerConv(WDML_INSTANCE* pInstance, HWND hwndClient,
HWND hwndServerName, HSZ hszApp, HSZ hszTopic)
{
WNDCLASSEXA wndclass;
HWND hwndServerConv;
WDML_CONV* pConv;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_ServerConvProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szServerConvClassA;
wndclass.hIconSm = 0;
if (pInstance->unicode)
{
WNDCLASSEXW wndclass;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_ServerConvProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WDML_szServerConvClassW;
wndclass.hIconSm = 0;
RegisterClassExW(&wndclass);
RegisterClassExA(&wndclass);
hwndServerConv = CreateWindowW(WDML_szServerConvClassW, 0,
WS_CHILD, 0, 0, 0, 0,
hwndServerName, 0, 0, 0);
}
else
{
WNDCLASSEXA wndclass;
wndclass.cbSize = sizeof(wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = WDML_ServerConvProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.hInstance = 0;
wndclass.hIcon = 0;
wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = WDML_szServerConvClassA;
wndclass.hIconSm = 0;
RegisterClassExA(&wndclass);
hwndServerConv = CreateWindowA(szServerConvClassA, 0,
WS_CHILD, 0, 0, 0, 0,
hwndServerName, 0, 0, 0);
hwndServerConv = CreateWindowA(WDML_szServerConvClassA, 0,
WS_CHILD, 0, 0, 0, 0,
hwndServerName, 0, 0, 0);
}
TRACE("Created convServer=%04x (nameServer=%04x) for instance=%08lx\n",
hwndServerConv, hwndServerName, thisInstance->instanceID);
pConv = WDML_AddConv(thisInstance, WDML_SERVER_SIDE, hszApp, hszTopic, hwndClient, hwndServerConv);
hwndServerConv, hwndServerName, pInstance->instanceID);
SetWindowLongA(hwndServerConv, 0, (DWORD)thisInstance);
SetWindowLongA(hwndServerConv, 4, (DWORD)pConv);
/* this should be the only place using SendMessage for WM_DDE_ACK */
SendMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv,
PackDDElParam(WM_DDE_ACK, (UINT)hszApp, (UINT)hszTopic));
#if 0
if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
pConv = WDML_AddConv(pInstance, WDML_SERVER_SIDE, hszApp, hszTopic,
hwndClient, hwndServerConv);
if (pConv)
{
/* confirm connection...
* FIXME: a better way would be to check for any incoming message if the conversation
* exists (and/or) has been confirmed...
* Anyway, always pretend we use a connection from a different instance...
SetWindowLongA(hwndServerConv, GWL_WDML_INSTANCE, (DWORD)pInstance);
SetWindowLongA(hwndServerConv, GWL_WDML_CONVERSATION, (DWORD)pConv);
/* this should be the only place using SendMessage for WM_DDE_ACK */
SendMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv,
PackDDElParam(WM_DDE_ACK,
WDML_MakeAtomFromHsz(hszApp),
WDML_MakeAtomFromHsz(hszTopic)));
/* we assume we're connected since we've sent an answer...
* I'm not sure what we can do... it doesn't look like the return value
* of SendMessage is used... sigh...
*/
(thisInstance->callback)(XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv, hszApp, hszTopic, 0, 0, 0);
pConv->wStatus |= ST_CONNECTED;
}
#endif
return TRUE;
else
{
DestroyWindow(hwndServerConv);
}
return pConv;
}
/******************************************************************
......@@ -383,8 +378,8 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w
HWND hwndClient;
HSZ hszApp, hszTop;
HDDEDATA hDdeData = 0;
WDML_INSTANCE* thisInstance;
UINT uiLow, uiHi;
WDML_INSTANCE* pInstance;
UINT uiLo, uiHi;
switch (iMsg)
{
......@@ -394,68 +389,97 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w
LOWORD(lParam) -- application atom
HIWORD(lParam) -- topic atom */
TRACE("WM_DDE_INITIATE message received in the Server Proc!\n");
TRACE("WM_DDE_INITIATE message received!\n");
hwndClient = (HWND)wParam;
pInstance = WDML_GetInstanceFromWnd(hwndServer);
TRACE("idInst=%ld, threadID=0x%lx\n", pInstance->instanceID, GetCurrentThreadId());
if (!pInstance) return 0;
/* don't free DDEParams, since this is a broadcast */
UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLow, &uiHi);
hszApp = (HSZ)uiLow;
hszTop = (HSZ)uiHi;
UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLo, &uiHi);
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndServer, 0);
TRACE("idInst=%ld, ProcessID=0x%lx\n", thisInstance->instanceID, GetCurrentProcessId());
hszApp = WDML_MakeHszFromAtom(pInstance, uiLo);
hszTop = WDML_MakeHszFromAtom(pInstance, uiHi);
if (hszApp && hszTop)
if (!(pInstance->CBFflags & CBF_FAIL_CONNECTIONS))
{
/* pass on to the callback */
if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
BOOL self = FALSE;
CONVCONTEXT cc;
CONVCONTEXT* pcc = NULL;
WDML_CONV* pConv;
char buf[256];
if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) &&
WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer))
{
self = TRUE;
}
/* FIXME: so far, we don't grab distant convcontext, so only check if remote is
* handled under DDEML, and if so build a default context
*/
if ((GetClassNameA(hwndClient, buf, sizeof(buf)) &&
strcmp(buf, WDML_szClientConvClassA) == 0) ||
(GetClassNameW(hwndClient, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) &&
lstrcmpW((LPWSTR)buf, WDML_szClientConvClassW) == 0))
{
pcc = &cc;
memset(pcc, 0, sizeof(*pcc));
pcc->cb = sizeof(*pcc);
pcc->iCodePage = IsWindowUnicode(hwndClient) ? CP_WINUNICODE : CP_WINANSI;
}
if ((pInstance->CBFflags & CBF_FAIL_SELFCONNECTIONS) && self)
{
TRACE("Don't do self connection as requested\n");
}
else if (hszApp && hszTop)
{
WDML_SERVER* pServer = (WDML_SERVER*)GetWindowLongA(hwndServer, GWL_WDML_SERVER);
TRACE("calling the Callback, type = XTYP_CONNECT, CB=0x%lx\n",
(DWORD)thisInstance->callback);
hDdeData = (thisInstance->callback)(XTYP_CONNECT,
0, 0,
hszTop,
hszApp,
0, 0, 0);
if ((UINT)hDdeData)
/* check filters for name service */
if (!pServer->filterOn || DdeCmpStringHandles(pServer->hszService, hszApp) == 0)
{
WDML_CreateServerConv(thisInstance, hwndClient, hwndServer, hszApp, hszTop);
/* pass on to the callback */
hDdeData = WDML_InvokeCallback(pInstance, XTYP_CONNECT,
0, 0, hszTop, hszApp, 0, (DWORD)pcc, self);
if ((UINT)hDdeData)
{
pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
hszApp, hszTop);
if (pConv && pcc) pConv->wStatus |= ST_ISLOCAL;
}
}
}
}
else
{
/* pass on to the callback */
if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
else if (pInstance->servers)
{
TRACE("calling the Callback, type=XTYP_WILDCONNECT, CB=0x%lx\n",
(DWORD)thisInstance->callback);
hDdeData = (thisInstance->callback)(XTYP_WILDCONNECT,
0, 0,
hszTop,
hszApp,
0, 0, 0);
if ((UINT)hDdeData)
/* pass on to the callback */
hDdeData = WDML_InvokeCallback(pInstance, XTYP_WILDCONNECT,
0, 0, hszTop, hszApp, 0, (DWORD)pcc, self);
if (hDdeData == CBR_BLOCK)
{
/* MS doc is not consistent here */
FIXME("CBR_BLOCK returned for WILDCONNECT\n");
}
else if ((UINT)hDdeData != 0)
{
HSZPAIR* hszp;
hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL);
if (hszp)
{
int i;
for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++)
{
WDML_CreateServerConv(thisInstance, hwndClient, hwndServer,
hszp[i].hszSvc, hszp[i].hszTopic);
}
pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
hszp[i].hszSvc, hszp[i].hszTopic);
if (pConv && pcc) pConv->wStatus |= ST_ISLOCAL;
}
DdeUnaccessData(hDdeData);
}
}
}
}
/*
billx: make a conv and add it to the server list -
this can be delayed when link is created for the conv. NO NEED !!!
......@@ -489,119 +513,126 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w
}
/******************************************************************
* WDML_ServerHandleRequest
* WDML_ServerQueueRequest
*
*
*/
static LRESULT WDML_ServerHandleRequest(WDML_INSTANCE* thisInstance, WDML_CONV* pConv,
HWND hwndServer, HWND hwndClient, LPARAM lParam)
static WDML_XACT* WDML_ServerQueueRequest(WDML_CONV* pConv, LPARAM lParam)
{
UINT uiLow, uiHi;
HSZ hszItem;
HDDEDATA hDdeData;
UINT uiLo, uiHi;
WDML_XACT* pXAct;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLow, &uiHi);
UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLo, &uiHi);
hszItem = (HSZ)uiHi;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST,
uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi));
if (pXAct) pXAct->atom = uiHi;
return pXAct;
}
hDdeData = 0;
if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
/******************************************************************
* WDML_ServerHandleRequest
*
*
*/
static WDML_QUEUE_STATE WDML_ServerHandleRequest(WDML_CONV* pConv, WDML_XACT* pXAct)
{
HDDEDATA hDdeData = 0;
WDML_QUEUE_STATE ret = WDML_QS_HANDLED;
if (!(pConv->instance->CBFflags & CBF_FAIL_REQUESTS))
{
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n",
thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_REQUEST);
hDdeData = (thisInstance->callback)(XTYP_REQUEST, uiLow, (HCONV)pConv,
pConv->hszTopic, hszItem, 0, 0, 0);
hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_REQUEST, pXAct->wFmt, (HCONV)pConv,
pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
}
if (hDdeData)
switch (hDdeData)
{
HGLOBAL hMem = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE);
if (!PostMessageA(hwndClient, WM_DDE_DATA, (WPARAM)hwndServer,
ReuseDDElParam(lParam, WM_DDE_REQUEST, WM_DDE_DATA, (UINT)hMem, (UINT)hszItem)))
{
DdeFreeDataHandle(hDdeData);
GlobalFree(hMem);
case 0:
WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, FALSE, pXAct->hszItem,
pXAct->lParam, WM_DDE_REQUEST);
break;
case CBR_BLOCK:
ret = WDML_QS_BLOCK;
break;
default:
{
HGLOBAL hMem = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE);
if (!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
ReuseDDElParam(pXAct->lParam, WM_DDE_REQUEST, WM_DDE_DATA,
(UINT)hMem, (UINT)pXAct->atom)))
{
DdeFreeDataHandle(hDdeData);
GlobalFree(hMem);
}
}
break;
}
else
{
DDEACK ddeAck;
ddeAck.bAppReturnCode = 0;
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
ddeAck.fAck = FALSE;
TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative");
PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
ReuseDDElParam(lParam, WM_DDE_REQUEST, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
}
return 0;
WDML_DecHSZ(pConv->instance, pXAct->hszItem);
return ret;
}
/******************************************************************
* WDML_ServerHandleAdvise
* WDML_ServerQueueAdvise
*
*
*/
static LRESULT WDML_ServerHandleAdvise(WDML_INSTANCE* thisInstance, WDML_CONV* pConv,
HWND hwndServer, HWND hwndClient, LPARAM lParam)
static WDML_XACT* WDML_ServerQueueAdvise(WDML_CONV* pConv, LPARAM lParam)
{
UINT uiLo, uiHi, uType;
HGLOBAL hDdeAdvise;
HSZ hszItem;
WDML_LINK* pLink;
DDEADVISE* pDdeAdvise;
HDDEDATA hDdeData;
DDEACK ddeAck;
UINT uiLo, uiHi;
WDML_XACT* pXAct;
/* XTYP_ADVSTART transaction:
establish link and save link info to InstanceInfoTable */
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi);
hDdeAdvise = (HGLOBAL)uiLo;
hszItem = (HSZ)uiHi; /* FIXME: it should be a global atom */
if (!pConv)
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE,
0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
if (pXAct)
{
ERR("Got an advise on a not known conversation, dropping request\n");
FreeDDElParam(WM_DDE_ADVISE, lParam);
return 0;
pXAct->hMem = (HGLOBAL)uiLo;
pXAct->atom = uiHi;
}
return pXAct;
}
pDdeAdvise = (DDEADVISE*)GlobalLock(hDdeAdvise);
/******************************************************************
* WDML_ServerHandleAdvise
*
*
*/
static WDML_QUEUE_STATE WDML_ServerHandleAdvise(WDML_CONV* pConv, WDML_XACT* pXAct)
{
UINT uType;
WDML_LINK* pLink;
DDEADVISE* pDdeAdvise;
HDDEDATA hDdeData;
BOOL fAck;
pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->hMem);
uType = XTYP_ADVSTART |
(pDdeAdvise->fDeferUpd ? XTYPF_NODATA : 0) |
(pDdeAdvise->fAckReq ? XTYPF_ACKREQ : 0);
hDdeData = 0;
if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
{
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x, uFmt=%x\n",
thisInstance->instanceID, (DWORD)thisInstance->callback,
uType, pDdeAdvise->cfFormat);
hDdeData = (thisInstance->callback)(XTYP_ADVSTART, pDdeAdvise->cfFormat, (HCONV)pConv,
pConv->hszTopic, hszItem, 0, 0, 0);
hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_ADVSTART, pDdeAdvise->cfFormat,
(HCONV)pConv, pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
}
else
{
hDdeData = 0;
}
ddeAck.bAppReturnCode = 0;
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
if ((UINT)hDdeData || TRUE) /* FIXME (from Corel ?) some apps don't return this value */
if ((UINT)hDdeData)
{
ddeAck.fAck = TRUE;
fAck = TRUE;
/* billx: first to see if the link is already created. */
pLink = WDML_FindLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE,
hszItem, pDdeAdvise->cfFormat);
pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
pXAct->hszItem, pDdeAdvise->cfFormat);
if (pLink != NULL)
{
......@@ -612,130 +643,135 @@ static LRESULT WDML_ServerHandleAdvise(WDML_INSTANCE* thisInstance, WDML_CONV* p
{
TRACE("Adding Link with hConv=0x%lx\n", (DWORD)pConv);
WDML_AddLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE,
uType, hszItem, pDdeAdvise->cfFormat);
WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
uType, pXAct->hszItem, pDdeAdvise->cfFormat);
}
}
else
{
TRACE("No data returned from the Callback\n");
ddeAck.fAck = FALSE;
fAck = FALSE;
}
GlobalUnlock(hDdeAdvise);
if (ddeAck.fAck)
GlobalFree(hDdeAdvise);
TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative");
PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
ReuseDDElParam(lParam, WM_DDE_ADVISE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
GlobalUnlock(pXAct->hMem);
if (fAck)
GlobalFree(pXAct->hMem);
WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, fAck, pXAct->atom, pXAct->lParam, WM_DDE_ADVISE);
WDML_DecHSZ(pConv->instance, pXAct->hszItem);
return 0L;
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_ServerHandleUnadvise
* WDML_ServerQueueUnadvise
*
*
*/
static LRESULT WDML_ServerHandleUnadvise(WDML_INSTANCE* thisInstance, WDML_CONV* pConv,
HWND hwndServer, HWND hwndClient, LPARAM lParam)
static WDML_XACT* WDML_ServerQueueUnadvise(WDML_CONV* pConv, LPARAM lParam)
{
UINT uiLo, uiHi;
HSZ hszItem;
WDML_LINK* pLink;
DDEACK ddeAck;
WDML_XACT* pXAct;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
/* billx: XTYP_ADVSTOP transaction */
UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
/* uiLow: wFmt */
hszItem = (HSZ)uiHi; /* FIXME: it should be a global atom */
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE,
uiLo, WDML_MakeHszFromAtom(pConv->instance, uiHi));
if (pXAct) pXAct->atom = uiHi;
return pXAct;
}
/******************************************************************
* WDML_ServerHandleUnadvise
*
*
*/
static WDML_QUEUE_STATE WDML_ServerHandleUnadvise(WDML_CONV* pConv, WDML_XACT* pXAct)
{
WDML_LINK* pLink;
if (hszItem == (HSZ)0 || uiLo == 0)
if (pXAct->hszItem == (HSZ)0 || pXAct->wFmt == 0)
{
ERR("Unsupported yet options (null item or clipboard format\n");
ERR("Unsupported yet options (null item or clipboard format)\n");
return WDML_QS_ERROR;
}
pLink = WDML_FindLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, hszItem, uiLo);
pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
pXAct->hszItem, pXAct->wFmt);
if (pLink == NULL)
{
ERR("Couln'd find link for %08lx, dropping request\n", (DWORD)hszItem);
FreeDDElParam(WM_DDE_UNADVISE, lParam);
return 0;
ERR("Couln'd find link for %08lx, dropping request\n", (DWORD)pXAct->hszItem);
FreeDDElParam(WM_DDE_UNADVISE, pXAct->lParam);
return WDML_QS_ERROR;
}
/* callback shouldn't be invoked if CBF_FAIL_ADVISES is on. */
if (thisInstance && thisInstance->callback != NULL &&
!(thisInstance->CBFflags & CBF_SKIP_DISCONNECTS) /* && thisInstance->Process_id == GetCurrentProcessId() */)
if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
{
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n",
thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_ADVSTOP);
(thisInstance->callback)(XTYP_ADVSTOP, uiLo, (HCONV)pConv, pConv->hszTopic,
hszItem, 0, 0, 0);
WDML_InvokeCallback(pConv->instance, XTYP_ADVSTOP, pXAct->wFmt, (HCONV)pConv,
pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
}
WDML_RemoveLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, hszItem, uiLo);
WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
pXAct->hszItem, pXAct->wFmt);
/* send back ack */
ddeAck.bAppReturnCode = 0;
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
ddeAck.fAck = TRUE;
PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
ReuseDDElParam(lParam, WM_DDE_UNADVISE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, TRUE, pXAct->atom,
pXAct->lParam, WM_DDE_UNADVISE);
return 0;
WDML_DecHSZ(pConv->instance, pXAct->hszItem);
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_ServerHandleExecute
* WDML_QueueExecute
*
*
*/
static LRESULT WDML_ServerHandleExecute(WDML_INSTANCE* thisInstance, WDML_CONV* pConv,
HWND hwndServer, HWND hwndClient, LPARAM lParam)
static WDML_XACT* WDML_ServerQueueExecute(WDML_CONV* pConv, LPARAM lParam)
{
DDEACK ddeAck;
HDDEDATA hDdeData;
WDML_XACT* pXAct;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
if (hwndClient != pConv->hwndClient)
WARN("hmmm source window (%04x)\n", hwndClient);
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
if (pXAct)
{
pXAct->hMem = (HGLOBAL)lParam;
}
return pXAct;
}
/******************************************************************
* WDML_ServerHandleExecute
*
*
*/
static WDML_QUEUE_STATE WDML_ServerHandleExecute(WDML_CONV* pConv, WDML_XACT* pXAct)
{
HDDEDATA hDdeData = DDE_FNOTPROCESSED;
BOOL fAck = FALSE, fBusy = FALSE;
hDdeData = 0;
if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
if (!(pConv->instance->CBFflags & CBF_FAIL_EXECUTES))
{
LPVOID ptr = GlobalLock((HGLOBAL)lParam);
LPVOID ptr = GlobalLock(pXAct->hMem);
if (ptr)
{
hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize((HGLOBAL)lParam),
hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize(pXAct->hMem),
0, 0, CF_TEXT, 0);
GlobalUnlock((HGLOBAL)lParam);
GlobalUnlock(pXAct->hMem);
}
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n",
thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_EXECUTE);
hDdeData = (thisInstance->callback)(XTYP_EXECUTE, 0, (HCONV)pConv, pConv->hszTopic, 0,
hDdeData, 0L, 0L);
hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_EXECUTE, 0, (HCONV)pConv,
pConv->hszTopic, 0, hDdeData, 0L, 0L);
}
ddeAck.bAppReturnCode = 0;
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
ddeAck.fAck = FALSE;
switch ((UINT)hDdeData)
{
case DDE_FACK:
ddeAck.fAck = TRUE;
fAck = TRUE;
break;
case DDE_FBUSY:
ddeAck.fBusy = TRUE;
fBusy = TRUE;
break;
default:
WARN("Bad result code\n");
......@@ -743,63 +779,69 @@ static LRESULT WDML_ServerHandleExecute(WDML_INSTANCE* thisInstance, WDML_CONV*
case DDE_FNOTPROCESSED:
break;
}
PostMessageA(pConv->hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
PackDDElParam(WM_DDE_ACK, *((WORD*)&ddeAck), lParam));
WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, pXAct->hMem, 0, 0);
return 0;
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_ServerHandlePoke
* WDML_ServerQueuePoke
*
*
*/
static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pConv,
HWND hwndServer, HWND hwndClient, LPARAM lParam)
static WDML_XACT* WDML_ServerQueuePoke(WDML_CONV* pConv, LPARAM lParam)
{
UINT uiLo, uiHi;
HSZ hszItem;
DDEACK ddeAck;
WDML_XACT* pXAct;
UnpackDDElParam(WM_DDE_POKE, lParam, &uiLo, &uiHi);
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE,
0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
if (pXAct)
{
pXAct->atom = uiHi;
pXAct->hMem = (HGLOBAL)uiLo;
}
return pXAct;
}
/******************************************************************
* WDML_ServerHandlePoke
*
*
*/
static WDML_QUEUE_STATE WDML_ServerHandlePoke(WDML_CONV* pConv, WDML_XACT* pXAct)
{
DDEPOKE* pDdePoke;
HDDEDATA hDdeData;
BOOL fBusy = FALSE, fAck = FALSE;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
hszItem = (HSZ)uiHi;
pDdePoke = (DDEPOKE*)GlobalLock((HGLOBAL)uiLo);
pDdePoke = (DDEPOKE*)GlobalLock(pXAct->hMem);
if (!pDdePoke)
{
return 0;
return WDML_QS_ERROR;
}
ddeAck.bAppReturnCode = 0;
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
ddeAck.fAck = FALSE;
if (thisInstance && thisInstance->callback != NULL)
if (!(pConv->instance->CBFflags & CBF_FAIL_POKES))
{
hDdeData = DdeCreateDataHandle(thisInstance->instanceID, pDdePoke->Value,
GlobalSize((HGLOBAL)uiLo) - sizeof(DDEPOKE) + 1,
hDdeData = DdeCreateDataHandle(pConv->instance->instanceID, pDdePoke->Value,
GlobalSize(pXAct->hMem) - sizeof(DDEPOKE) + 1,
0, 0, pDdePoke->cfFormat, 0);
if (hDdeData)
{
HDDEDATA hDdeDataOut;
TRACE("calling callback XTYP_POKE, idInst=%ld\n",
thisInstance->instanceID);
hDdeDataOut = (thisInstance->callback)(XTYP_POKE,
pDdePoke->cfFormat, (HCONV)pConv,
pConv->hszTopic, (HSZ)uiHi,
hDdeData, 0, 0);
hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_POKE, pDdePoke->cfFormat,
(HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
hDdeData, 0, 0);
switch ((UINT)hDdeDataOut)
{
case DDE_FACK:
ddeAck.fAck = TRUE;
fAck = TRUE;
break;
case DDE_FBUSY:
ddeAck.fBusy = TRUE;
fBusy = TRUE;
break;
default:
FIXME("Unsupported returned value %08lx\n", (DWORD)hDdeDataOut);
......@@ -810,15 +852,29 @@ static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pCo
DdeFreeDataHandle(hDdeData);
}
}
GlobalUnlock((HGLOBAL)uiLo);
if (!ddeAck.fAck)
GlobalFree((HGLOBAL)uiHi);
GlobalUnlock(pXAct->hMem);
PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
ReuseDDElParam(lParam, WM_DDE_POKE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem));
if (!fAck)
GlobalFree(pXAct->hMem);
WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, pXAct->atom, pXAct->lParam, WM_DDE_POKE);
WDML_DecHSZ(pConv->instance, pXAct->hszItem);
return WDML_QS_HANDLED;
}
return 0L;
/******************************************************************
* WDML_ServerQueueTerminate
*
*
*/
static WDML_XACT* WDML_ServerQueueTerminate(WDML_CONV* pConv, LPARAM lParam)
{
WDML_XACT* pXAct;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
return pXAct;
}
/******************************************************************
......@@ -826,34 +882,69 @@ static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pCo
*
*
*/
static LRESULT WDML_ServerHandleTerminate(WDML_INSTANCE* thisInstance, WDML_CONV* pConv,
HWND hwndServer, HWND hwndClient, LPARAM lParam)
static WDML_QUEUE_STATE WDML_ServerHandleTerminate(WDML_CONV* pConv, WDML_XACT* pXAct)
{
UINT uiLo, uiHi;
HSZ hszApp, hszTop;
/* billx: two things to remove: the conv, and associated links.
* Respond with another WM_DDE_TERMINATE iMsg.
*/
if (!(pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS))
{
WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv, 0, 0,
0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
}
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
PostMessageA(pConv->hwndClient, WM_DDE_TERMINATE, (WPARAM)pConv->hwndServer, 0);
WDML_RemoveConv(pConv, WDML_SERVER_SIDE);
TRACE("WM_DDE_TERMINATE!\n");
/* XTYP_DISCONNECT transaction */
/* billx: two things to remove: the conv, and associated links.
callback shouldn't be called if CBF_SKIP_DISCONNECTS is on.
Respond with another WM_DDE_TERMINATE iMsg.*/
/* don't free DDEParams, since this is a broadcast */
UnpackDDElParam(WM_DDE_TERMINATE, lParam, &uiLo, &uiHi);
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_ServerHandle
*
*
*/
static WDML_QUEUE_STATE WDML_ServerHandle(WDML_CONV* pConv, WDML_XACT* pXAct)
{
WDML_QUEUE_STATE qs = WDML_QS_ERROR;
switch (pXAct->ddeMsg)
{
case WM_DDE_INITIATE:
FIXME("WM_DDE_INITIATE shouldn't be there!\n");
break;
case WM_DDE_REQUEST:
qs = WDML_ServerHandleRequest(pConv, pXAct);
break;
case WM_DDE_ADVISE:
qs = WDML_ServerHandleAdvise(pConv, pXAct);
break;
hszApp = (HSZ)uiLo;
hszTop = (HSZ)uiHi;
case WM_DDE_UNADVISE:
qs = WDML_ServerHandleUnadvise(pConv, pXAct);
break;
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_UNREGISTER, hszApp, hszTop);
/* PostMessageA(hwndClient, WM_DDE_TERMINATE, (WPARAM)hwndServer, (LPARAM)hConv); */
WDML_RemoveAllLinks(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE);
WDML_RemoveConv(thisInstance, WDML_SERVER_SIDE, (HCONV)pConv);
/* DestroyWindow(hwnd); don't destroy it now, we may still need it. */
case WM_DDE_EXECUTE:
qs = WDML_ServerHandleExecute(pConv, pXAct);
break;
return 0;
case WM_DDE_POKE:
qs = WDML_ServerHandlePoke(pConv, pXAct);
break;
case WM_DDE_TERMINATE:
qs = WDML_ServerHandleTerminate(pConv, pXAct);
break;
case WM_DDE_ACK:
WARN("Shouldn't receive a ACK message (never requests them). Ignoring it\n");
break;
default:
FIXME("Unsupported message %d\n", pXAct->ddeMsg);
}
return qs;
}
/******************************************************************
......@@ -863,52 +954,74 @@ static LRESULT WDML_ServerHandleTerminate(WDML_INSTANCE* thisInstance, WDML_CONV
*/
static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
WDML_INSTANCE* thisInstance;
WDML_INSTANCE* pInstance;
WDML_CONV* pConv;
WDML_XACT* pXAct = NULL;
if (iMsg == WM_DESTROY)
{
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConvFromWnd(hwndServer);
if (pConv && !(pConv->wStatus & ST_TERMINATED))
{
WDML_ServerHandleTerminate(pConv, NULL);
}
LeaveCriticalSection(&WDML_CritSect);
}
if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST)
{
return DefWindowProcA(hwndServer, iMsg, wParam, lParam);
}
TRACE("About to wait... \n");
EnterCriticalSection(&WDML_CritSect);
if (!WDML_WaitForMutex(handle_mutex))
pInstance = WDML_GetInstanceFromWnd(hwndServer);
pConv = WDML_GetConvFromWnd(hwndServer);
if (!pConv)
{
return 0;
ERR("Got a message (%u) on a not known conversation, dropping request\n", iMsg);
goto theError;
}
if (pConv->hwndClient != (HWND)wParam || pConv->hwndServer != hwndServer)
{
ERR("mismatch between C/S windows and converstation\n");
goto theError;
}
if (pConv->instance != pInstance || pConv->instance == NULL)
{
ERR("mismatch in instances\n");
goto theError;
}
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndServer, 0);
pConv = (WDML_CONV*)GetWindowLongA(hwndServer, 4);
switch (iMsg)
{
case WM_DDE_INITIATE:
FIXME("WM_DDE_INITIATE message received in the ServerConv Proc!\n");
FIXME("WM_DDE_INITIATE message received!\n");
break;
case WM_DDE_REQUEST:
WDML_ServerHandleRequest(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
pXAct = WDML_ServerQueueRequest(pConv, lParam);
break;
case WM_DDE_ADVISE:
WDML_ServerHandleAdvise(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
pXAct = WDML_ServerQueueAdvise(pConv, lParam);
break;
case WM_DDE_UNADVISE:
WDML_ServerHandleUnadvise(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
pXAct = WDML_ServerQueueUnadvise(pConv, lParam);
break;
case WM_DDE_EXECUTE:
WDML_ServerHandleExecute(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
pXAct = WDML_ServerQueueExecute(pConv, lParam);
break;
case WM_DDE_POKE:
WDML_ServerHandlePoke(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
pXAct = WDML_ServerQueuePoke(pConv, lParam);
break;
case WM_DDE_TERMINATE:
WDML_ServerHandleTerminate(thisInstance, pConv, hwndServer, (HWND)wParam, lParam);
pXAct = WDML_ServerQueueTerminate(pConv, lParam);
break;
case WM_DDE_ACK:
......@@ -918,8 +1031,20 @@ static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM w
default:
FIXME("Unsupported message %d\n", iMsg);
}
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
if (pXAct)
{
pXAct->lParam = lParam;
if (WDML_ServerHandle(pConv, pXAct) == WDML_QS_BLOCK)
{
WDML_QueueTransaction(pConv, pXAct);
}
else
{
WDML_FreeTransaction(pInstance, pXAct, TRUE);
}
}
theError:
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
......@@ -26,7 +26,7 @@ debug_channels (accel caret class clipboard combo cursor dc dde ddeml dialog dri
@ stdcall BringWindowToTop(long) BringWindowToTop
@ stdcall BroadcastSystemMessage(long ptr long long long) BroadcastSystemMessage
@ stdcall CalcChildScroll(long long) CalcChildScroll
@ stub CallMsgFilter
@ stdcall CallMsgFilter(ptr long) CallMsgFilterA
@ stdcall CallMsgFilterA(ptr long) CallMsgFilterA
@ stdcall CallMsgFilterW(ptr long) CallMsgFilterW
@ stdcall CallNextHookEx(long long long long) CallNextHookEx
......@@ -107,8 +107,8 @@ debug_channels (accel caret class clipboard combo cursor dc dde ddeml dialog dri
@ stdcall DdeConnect(long long long ptr) DdeConnect
@ stdcall DdeConnectList(long long long long ptr) DdeConnectList
@ stdcall DdeCreateDataHandle(long ptr long long long long long) DdeCreateDataHandle
@ stdcall DdeCreateStringHandleA(long str long) DdeCreateStringHandleA
@ stdcall DdeCreateStringHandleW(long wstr long) DdeCreateStringHandleW
@ stdcall DdeCreateStringHandleA(long ptr long) DdeCreateStringHandleA
@ stdcall DdeCreateStringHandleW(long ptr long) DdeCreateStringHandleW
@ stdcall DdeDisconnect(long) DdeDisconnect
@ stdcall DdeDisconnectList(long) DdeDisconnectList
@ stdcall DdeEnableCallback(long long long) DdeEnableCallback
......
......@@ -262,6 +262,9 @@ static void thread_detach(void)
{
HQUEUE16 hQueue = GetThreadQueue16( 0 );
extern void WDML_NotifyThreadDetach(void);
WDML_NotifyThreadDetach();
if (hQueue)
{
TIMER_RemoveQueueTimers( hQueue );
......
......@@ -177,6 +177,8 @@ extern "C" {
#define TIMEOUT_ASYNC 0xFFFFFFFF
#define CADV_LATEACK 0xFFFF
/**************************************************
End of Message Types Section
......@@ -332,6 +334,7 @@ BOOL WINAPI DdeFreeStringHandle(DWORD,HSZ);
BOOL WINAPI DdeFreeDataHandle(HDDEDATA);
BOOL WINAPI DdeKeepStringHandle(DWORD,HSZ);
HDDEDATA WINAPI DdeClientTransaction(LPBYTE,DWORD,HCONV,HSZ,UINT,UINT,DWORD,LPDWORD);
BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction);
BOOL WINAPI DdeImpersonateClient(HCONV);
BOOL WINAPI DdePostAdvise(DWORD,HSZ,HSZ);
HDDEDATA WINAPI DdeAddData(HDDEDATA,LPBYTE,DWORD,DWORD);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment