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 = \ ...@@ -37,7 +37,9 @@ RC_SRCS16 = \
resources/mouse.rc \ resources/mouse.rc \
resources/version16.rc resources/version16.rc
GLUE = thunk.c GLUE = \
dde/ddeml16.c \
thunk.c
EXTRA_OBJS = \ EXTRA_OBJS = \
$(TOPOBJDIR)/controls/controls.o \ $(TOPOBJDIR)/controls/controls.o \
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "wingdi.h" #include "wingdi.h"
#include "winuser.h" #include "winuser.h"
#include "winerror.h" #include "winerror.h"
#include "winnls.h"
#include "dde.h" #include "dde.h"
#include "ddeml.h" #include "ddeml.h"
#include "debugtools.h" #include "debugtools.h"
...@@ -24,7 +25,8 @@ ...@@ -24,7 +25,8 @@
DEFAULT_DEBUG_CHANNEL(ddeml); DEFAULT_DEBUG_CHANNEL(ddeml);
static LRESULT CALLBACK WDML_ClientProc(HWND, UINT, WPARAM, LPARAM); /* only for one client, not conv list */ 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 * DdeConnectList [USER32.@] Establishes conversation with DDE servers
...@@ -44,7 +46,7 @@ HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic, ...@@ -44,7 +46,7 @@ HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
HCONVLIST hConvList, LPCONVCONTEXT pCC) HCONVLIST hConvList, LPCONVCONTEXT pCC)
{ {
FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic, FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
hConvList,pCC); hConvList, pCC);
return (HCONVLIST)1; return (HCONVLIST)1;
} }
...@@ -53,19 +55,22 @@ HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic, ...@@ -53,19 +55,22 @@ HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic,
*/ */
HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev) HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev)
{ {
FIXME("(%d,%d): stub\n",hConvList,hConvPrev); FIXME("(%d,%d): stub\n", hConvList, hConvPrev);
return 0; return 0;
} }
/****************************************************************************** /******************************************************************************
* DdeDisconnectList [USER32.@] Destroys list and terminates conversations * DdeDisconnectList [USER32.@] Destroys list and terminates conversations
* *
*
* PARAMS
* hConvList [I] Handle to conversation list
*
* RETURNS * RETURNS
* Success: TRUE * Success: TRUE
* Failure: FALSE * Failure: FALSE
*/ */
BOOL WINAPI DdeDisconnectList( BOOL WINAPI DdeDisconnectList(HCONVLIST hConvList)
HCONVLIST hConvList) /* [in] Handle to conversation list */
{ {
FIXME("(%d): stub\n", hConvList); FIXME("(%d): stub\n", hConvList);
return TRUE; return TRUE;
...@@ -79,103 +84,133 @@ HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic, ...@@ -79,103 +84,133 @@ HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic,
{ {
HWND hwndClient; HWND hwndClient;
LPARAM lParam = 0; LPARAM lParam = 0;
UINT uiLow, uiHi; WDML_INSTANCE* pInstance;
WNDCLASSEXA wndclass; WDML_CONV* pConv = NULL;
WDML_INSTANCE* thisInstance; ATOM aSrv = 0, aTpc = 0;
WDML_CONV* pConv;
TRACE("(0x%lx,%d,%d,%p)\n",idInst,hszService,hszTopic,pCC);
thisInstance = WDML_FindInstance(idInst); TRACE("(0x%lx,0x%x,0x%x,%p)\n", idInst, hszService, hszTopic, pCC);
if (!thisInstance)
EnterCriticalSection(&WDML_CritSect);
pInstance = WDML_GetInstance(idInst);
if (!pInstance)
{ {
return 0; goto theEnd;
} }
/* make sure this conv is never created */ /* 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) if (pConv != NULL)
{ {
ERR("This Conv already exists: (0x%lx)\n", (DWORD)pConv); ERR("This Conv already exists: (0x%lx)\n", (DWORD)pConv);
return (HCONV)pConv; goto theEnd;
} }
/* we need to establish a conversation with /* we need to establish a conversation with
server, so create a window for it */ server, so create a window for it */
wndclass.cbSize = sizeof(wndclass); if (pInstance->unicode)
wndclass.style = 0; {
wndclass.lpfnWndProc = WDML_ClientProc; WNDCLASSEXW wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.cbSize = sizeof(wndclass);
wndclass.hInstance = 0; wndclass.style = 0;
wndclass.hIcon = 0; wndclass.lpfnWndProc = WDML_ClientProc;
wndclass.hCursor = 0; wndclass.cbClsExtra = 0;
wndclass.hbrBackground = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.lpszMenuName = NULL; wndclass.hInstance = 0;
wndclass.lpszClassName = szClientClassA; wndclass.hIcon = 0;
wndclass.hIconSm = 0; wndclass.hCursor = 0;
wndclass.hbrBackground = 0;
RegisterClassExA(&wndclass); 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, if (hszService)
PackDDElParam(WM_DDE_INITIATE, (UINT)hszService, (UINT)hszTopic)); {
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)) EnterCriticalSection(&WDML_CritSect);
FreeDDElParam(WM_DDE_INITIATE, lParam);
pInstance = WDML_GetInstance(idInst);
if (!pInstance)
{
goto theEnd;
}
TRACE("WM_DDE_INITIATE was processed\n"); TRACE("WM_DDE_INITIATE was processed\n");
/* At this point, Client WM_DDE_ACK should have saved hwndServer /* At this point, Client WM_DDE_ACK should have saved hwndServer
for this instance id and hwndClient if server responds. for this instance id and hwndClient if server responds.
So get HCONV and return it. And add it to conv list */ 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) if (pConv == NULL || pConv->hwndServer == 0)
{ {
ERR(".. but no Server window available\n"); ERR(".. but no Server window available\n");
return 0; pConv = NULL;
goto theEnd;
} }
pConv->wConvst = XST_CONNECTED;
/* finish init of pConv */ /* finish init of pConv */
if (pCC != NULL) if (pCC != NULL)
{ {
pConv->convContext = *pCC; pConv->convContext = *pCC;
} }
else
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))
{ {
ERR("DdeDisconnect(): PostMessage returned 0\n"); memset(&pConv->convContext, 0, sizeof(pConv->convContext));
return 0; 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) * DdeReconnect (DDEML.37)
...@@ -183,52 +218,116 @@ BOOL WINAPI DdeDisconnect(HCONV hConv) ...@@ -183,52 +218,116 @@ BOOL WINAPI DdeDisconnect(HCONV hConv)
*/ */
HCONV WINAPI DdeReconnect(HCONV hConv) HCONV WINAPI DdeReconnect(HCONV hConv)
{ {
FIXME("empty stub\n"); WDML_CONV* pConv;
return 0; 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 { theEnd:
WDML_QS_ERROR, WDML_QS_HANDLED, WDML_QS_PASS LeaveCriticalSection(&WDML_CritSect);
} WDML_QUEUE_STATE;
if (aSrv) GlobalDeleteAtom(aSrv);
if (aTpc) GlobalDeleteAtom(aTpc);
return (HCONV)pNewConv;
}
/****************************************************************** /******************************************************************
* WDML_QueueAdvise * WDML_ClientQueueAdvise
* *
* Creates and queue an WM_DDE_ADVISE transaction * 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; DDEADVISE* pDdeAdvise;
WDML_XACT* pXAct; WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_ADVSTART (with%s data) transaction\n", (wType & XTYPF_NODATA) ? "out" : ""); 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) if (!pXAct)
{
GlobalDeleteAtom(atom);
return NULL; return NULL;
}
pXAct->u.advise.wType = wType & ~0x0F; pXAct->wType = wType & ~0x0F;
pXAct->u.advise.wFmt = wFmt; pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
pXAct->u.advise.hszItem = hszItem;
pXAct->u.advise.hDdeAdvise = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE));
/* pack DdeAdvise */ /* pack DdeAdvise */
pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->u.advise.hDdeAdvise); pDdeAdvise = (DDEADVISE*)GlobalLock(pXAct->hMem);
pDdeAdvise->fAckReq = (wType & XTYPF_ACKREQ) ? TRUE : FALSE; pDdeAdvise->fAckReq = (wType & XTYPF_ACKREQ) ? TRUE : FALSE;
pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) ? TRUE : FALSE; pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) ? TRUE : FALSE;
pDdeAdvise->cfFormat = wFmt; pDdeAdvise->cfFormat = wFmt;
GlobalUnlock(pXAct->u.advise.hDdeAdvise); GlobalUnlock(pXAct->hMem);
WDML_QueueTransaction(pConv, pXAct); pXAct->lParam = PackDDElParam(WM_DDE_ADVISE, (UINT)pXAct->hMem, atom);
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;
}
return pXAct; return pXAct;
} }
...@@ -242,82 +341,78 @@ static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_ ...@@ -242,82 +341,78 @@ static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_
{ {
DDEACK ddeAck; DDEACK ddeAck;
UINT uiLo, uiHi; UINT uiLo, uiHi;
WORD wStatus; HSZ hsz;
if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer) if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer)
{ {
return WDML_QS_PASS; return WDML_QS_PASS;
} }
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 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; return WDML_QS_PASS;
GlobalDeleteAtom(uiHi); GlobalDeleteAtom(uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam);
wStatus = uiLo; WDML_ExtractAck(uiLo, &ddeAck);
ddeAck = *((DDEACK*)&wStatus);
if (ddeAck.fAck) if (ddeAck.fAck)
{ {
WDML_LINK* pLink; WDML_LINK* pLink;
/* billx: first to see if the link is already created. */ /* billx: first to see if the link is already created. */
pLink = WDML_FindLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE, pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->u.advise.hszItem, pXAct->u.advise.wFmt); pXAct->hszItem, pXAct->wFmt);
if (pLink != NULL) if (pLink != NULL)
{ {
/* we found a link, and only need to modify it in case it changes */ /* 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 else
{ {
TRACE("Adding Link with hConv = 0x%lx\n", (DWORD)pConv); WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
WDML_AddLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE, pXAct->wType, pXAct->hszItem, pXAct->wFmt);
pXAct->u.advise.wType, pXAct->u.advise.hszItem,
pXAct->u.advise.wFmt);
} }
} }
else else
{ {
TRACE("Returning TRUE on XTYP_ADVSTART - fAck was FALSE\n"); TRACE("Returning TRUE on XTYP_ADVSTART - fAck was FALSE\n");
GlobalFree(pXAct->u.advise.hDdeAdvise); GlobalFree(pXAct->hMem);
} }
pXAct->hDdeData = (HDDEDATA)1; pXAct->hDdeData = (HDDEDATA)1;
return WDML_QS_HANDLED; return WDML_QS_HANDLED;
} }
/****************************************************************** /******************************************************************
* WDML_QueueUnadvise * WDML_ClientQueueUnadvise
* *
* queues an unadvise transaction * 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; WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_ADVSTOP transaction\n"); TRACE("XTYP_ADVSTOP transaction\n");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_UNADVISE); atom = WDML_MakeAtomFromHsz(hszItem);
if (!pXAct) if (!atom) return NULL;
return NULL;
pXAct->u.unadvise.wFmt = wFmt;
pXAct->u.unadvise.hszItem = hszItem;
WDML_QueueTransaction(pConv, pXAct);
/* end advise loop: post WM_DDE_UNADVISE to server to terminate link pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE, wFmt, hszItem);
on the specified item. */ if (!pXAct)
if (!PostMessageA(pConv->hwndServer, WM_DDE_UNADVISE, (WPARAM)pConv->hwndClient,
PackDDElParam(WM_DDE_UNADVISE, wFmt, (UINT)hszItem)))
{ {
WDML_UnQueueTransaction(pConv, pXAct); GlobalDeleteAtom(atom);
WDML_FreeTransaction(pXAct);
return NULL; 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; return pXAct;
} }
...@@ -330,7 +425,7 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM ...@@ -330,7 +425,7 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM
{ {
DDEACK ddeAck; DDEACK ddeAck;
UINT uiLo, uiHi; UINT uiLo, uiHi;
WORD wStatus; HSZ hsz;
if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer) 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 ...@@ -338,14 +433,15 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM
} }
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 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; return WDML_QS_PASS;
FreeDDElParam(WM_DDE_ACK, msg->lParam);
GlobalDeleteAtom(uiHi); GlobalDeleteAtom(uiHi);
wStatus = uiLo; WDML_ExtractAck(uiLo, &ddeAck);
ddeAck = *((DDEACK*)&wStatus);
TRACE("WM_DDE_ACK received while waiting for a timeout\n"); 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 ...@@ -356,43 +452,37 @@ static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDM
else else
{ {
/* billx: remove the link */ /* billx: remove the link */
WDML_RemoveLink(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE, WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE,
pXAct->u.unadvise.hszItem, pXAct->u.unadvise.wFmt); pXAct->hszItem, pXAct->wFmt);
} }
pXAct->hDdeData = (HDDEDATA)1; pXAct->hDdeData = (HDDEDATA)1;
return WDML_QS_HANDLED; 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; WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_REQUEST transaction\n");
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_REQUEST);
if (!pXAct)
return NULL;
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 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, wFmt, hszItem);
* on the specified item. if (!pXAct)
*/
if (!PostMessageA(pConv->hwndServer, WM_DDE_REQUEST, (WPARAM)pConv->hwndClient,
PackDDElParam(WM_DDE_REQUEST, wFmt, (UINT)hszItem)))
{ {
WDML_UnQueueTransaction(pConv, pXAct); GlobalDeleteAtom(atom);
WDML_FreeTransaction(pXAct);
return NULL; return NULL;
} }
pXAct->lParam = PackDDElParam(WM_DDE_REQUEST, wFmt, atom);
return pXAct; return pXAct;
} }
...@@ -403,33 +493,49 @@ static WDML_XACT* WDML_QueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem) ...@@ -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) static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
{ {
DDEACK ddeAck; DDEACK ddeAck;
UINT uiLo, uiHi; WINE_DDEHEAD wdh;
WORD wStatus; 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) switch (msg->message)
{ {
case WM_DDE_ACK: case WM_DDE_ACK:
if (msg->wParam != pConv->hwndServer) GlobalDeleteAtom(uiHi);
return WDML_QS_PASS; WDML_ExtractAck(uiLo, &ddeAck);
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
wStatus = uiLo;
ddeAck = *((DDEACK*)&wStatus);
pXAct->hDdeData = 0; pXAct->hDdeData = 0;
if (ddeAck.fAck)
ERR("Positive answer should appear in NACK for a request, assuming negative\n");
TRACE("Negative answer...\n"); TRACE("Negative answer...\n");
/* FIXME: billx: we should return 0 and post a negatve WM_DDE_ACK. */
break; break;
case WM_DDE_DATA: 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); 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; return WDML_QS_PASS;
/* FIXME: memory clean up ? */ /* 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; break;
default: default:
...@@ -440,76 +546,105 @@ static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML ...@@ -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"); clientUnicode = IsWindowUnicode(pConv->hwndClient);
serverUnicode = IsWindowUnicode(pConv->hwndServer);
pXAct = WDML_AllocTransaction(pConv->thisInstance, WM_DDE_EXECUTE);
if (!pXAct)
return NULL;
if (cbData == (DWORD)-1) if (clientUnicode == serverUnicode)
{ {
HDDEDATA hDdeData = (HDDEDATA)pData; memSize = cbData;
DWORD dwSize; }
else
pData = DdeAccessData(hDdeData, &dwSize); {
if (pData) if (clientUnicode)
{ {
pXAct->u.execute.hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, dwSize); memSize = WideCharToMultiByte( CP_ACP, 0, pData, cbData, NULL, 0, NULL, NULL);
if (pXAct->u.execute.hMem) }
{ else
LPBYTE pDst; {
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); pDst = GlobalLock(hMem);
if (pDst) if (pDst)
{
if (clientUnicode == serverUnicode)
{
memcpy(pDst, pData, cbData);
}
else
{
if (clientUnicode)
{ {
memcpy(pDst, pData, dwSize); WideCharToMultiByte( CP_ACP, 0, pData, cbData, pDst, memSize, NULL, NULL);
GlobalUnlock(pXAct->u.execute.hMem);
} }
else else
{ {
GlobalFree(pXAct->u.execute.hMem); MultiByteToWideChar( CP_ACP, 0, pData, cbData, (LPWSTR)pDst, memSize);
pXAct->u.execute.hMem = 0;
} }
} }
DdeUnaccessData(hDdeData);
GlobalUnlock(hMem);
} }
else else
{ {
pXAct->u.execute.hMem = 0; GlobalFree(hMem);
hMem = 0;
} }
} }
else return hMem;
{ }
LPSTR ptr;
/******************************************************************
* 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); if (cbData == (DWORD)-1)
ptr = GlobalLock(pXAct->u.execute.hMem); {
if (ptr) HDDEDATA hDdeData = (HDDEDATA)pData;
pData = DdeAccessData(hDdeData, &cbData);
if (pData)
{ {
memcpy(ptr, pData, cbData); pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
GlobalUnlock(pXAct->u.execute.hMem); DdeUnaccessData(hDdeData);
} }
} }
else
WDML_QueueTransaction(pConv, pXAct);
if (!PostMessageA(pConv->hwndServer, WM_DDE_EXECUTE, (WPARAM)pConv->hwndClient,
pXAct->u.execute.hMem))
{ {
GlobalFree(pXAct->u.execute.hMem); pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pXAct);
TRACE("Returning FALSE on XTYP_EXECUTE - PostMessage returned FALSE\n");
return NULL;
} }
pXAct->lParam = pXAct->hMem;
return pXAct; return pXAct;
} }
...@@ -522,7 +657,6 @@ static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML ...@@ -522,7 +657,6 @@ static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML
{ {
DDEACK ddeAck; DDEACK ddeAck;
UINT uiLo, uiHi; UINT uiLo, uiHi;
WORD wStatus;
if (msg->message != WM_DDE_ACK || msg->wParam != pConv->hwndServer) 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 ...@@ -532,69 +666,64 @@ static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam); FreeDDElParam(WM_DDE_ACK, msg->lParam);
if (uiHi != pXAct->u.execute.hMem) if (uiHi != pXAct->hMem)
{ {
return WDML_QS_PASS; return WDML_QS_PASS;
} }
wStatus = uiLo; WDML_ExtractAck(uiLo, &ddeAck);
ddeAck = *((DDEACK*)&wStatus);
if (!ddeAck.fAck) if (!ddeAck.fAck)
{ {
GlobalFree(pXAct->u.execute.hMem); GlobalFree(pXAct->hMem);
} }
pXAct->hDdeData = (HDDEDATA)1; pXAct->hDdeData = (HDDEDATA)1;
return WDML_QS_HANDLED; return WDML_QS_HANDLED;
} }
/****************************************************************** /******************************************************************
* WDML_QueuePoke * WDML_ClientQueuePoke
* *
* *
*/ */
static WDML_XACT* WDML_QueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData, static WDML_XACT* WDML_ClientQueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData,
UINT wFmt, HSZ hszItem) UINT wFmt, HSZ hszItem)
{ {
WDML_XACT* pXAct; WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_POKE transaction\n"); 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) if (!pXAct)
{
GlobalDeleteAtom(atom);
return NULL; return NULL;
}
if (cbData == (DWORD)-1) if (cbData == (DWORD)-1)
{ {
pXAct->u.poke.hMem = (HDDEDATA)pData; pXAct->hMem = (HDDEDATA)pData;
} }
else else
{ {
DDEPOKE* ddePoke; DDEPOKE* ddePoke;
pXAct->u.poke.hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData); pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData);
ddePoke = GlobalLock(pXAct->u.poke.hMem); ddePoke = GlobalLock(pXAct->hMem);
if (ddePoke) if (ddePoke)
{ {
memcpy(ddePoke->Value, pData, cbData); memcpy(ddePoke->Value, pData, cbData);
ddePoke->fRelease = FALSE; /* FIXME: app owned ? */ ddePoke->fRelease = FALSE; /* FIXME: app owned ? */
ddePoke->cfFormat = wFmt; 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; return pXAct;
} }
...@@ -607,7 +736,7 @@ static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XA ...@@ -607,7 +736,7 @@ static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XA
{ {
DDEACK ddeAck; DDEACK ddeAck;
UINT uiLo, uiHi; UINT uiLo, uiHi;
WORD wStatus; HSZ hsz;
if (msg->message != WM_DDE_ACK && msg->wParam != pConv->hwndServer) 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 ...@@ -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); 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; return WDML_QS_PASS;
} }
FreeDDElParam(WM_DDE_ACK, msg->lParam); 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; pXAct->hDdeData = (HDDEDATA)TRUE;
return 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 * 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; UINT uiLo, uiHi;
HDDEDATA hDdeDataIn, hDdeDataOut; HDDEDATA hDdeDataIn, hDdeDataOut;
WDML_LINK* pLink; WDML_LINK* pLink;
WINE_DDEHEAD wdh;
HSZ hsz;
TRACE("WM_DDE_DATA message received in the Client Proc!\n"); TRACE("WM_DDE_DATA message received in the Client Proc!\n");
/* wParam -- sending window handle */ /* wParam -- sending window handle */
/* lParam -- hDdeData & item HSZ */ /* lParam -- hDdeData & item HSZ */
UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi); UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo);
hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
/* billx: /* billx:
* For hot link, data should be passed to its callback with * For hot link, data should be passed to its callback with
* XTYP_ADVDATA and callback should return the proper status. * 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) WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi,
{ msg->lParam, WM_DDE_DATA);
BOOL fRelease = FALSE; if (msg->lParam)
BOOL fAckReq = FALSE; msg->lParam = 0;
DDEDATA* pDdeData; }
else
/* item in the advise loop */ {
pConv = WDML_GetConv(pLink->hConv); GlobalDeleteAtom(uiHi);
if (pConv == NULL) }
{
continue; hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv,
} pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0);
if ((pDdeData = GlobalLock(uiLo)) != NULL) if (hDdeDataOut == (HDDEDATA)DDE_FACK)
{ {
fRelease = pDdeData->fRelease; pLink->hDdeData = hDdeDataIn;
fAckReq = pDdeData->fAckReq; }
} if (wdh.fRelease)
{
if (hDdeDataIn != 0) DdeFreeDataHandle(hDdeDataIn);
{
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_DecHSZ(pConv->instance, hsz);
if (msg->lParam) if (msg->lParam)
FreeDDElParam(WM_DDE_DATA, msg->lParam); FreeDDElParam(WM_DDE_DATA, msg->lParam);
...@@ -733,19 +869,28 @@ static WDML_QUEUE_STATE WDML_HandleReplyData(WDML_CONV* pConv, MSG* msg, HDDEDAT ...@@ -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; return WDML_QS_PASS;
/* billx: clean up the conv and associated links */ pConv->wStatus |= ST_TERMINATED;
WDML_RemoveAllLinks(pConv->thisInstance, (HCONV)pConv, WDML_CLIENT_SIDE); if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
WDML_RemoveConv(pConv->thisInstance, WDML_CLIENT_SIDE, (HCONV)pConv); {
DestroyWindow(msg->hwnd); 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; return WDML_QS_HANDLED;
} }
...@@ -756,7 +901,7 @@ static WDML_QUEUE_STATE WDML_HandleReplyTerminate(WDML_CONV* pConv, MSG* msg, HD ...@@ -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) 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; WDML_QUEUE_STATE qs;
if (pConv->transactions) if (pConv->transactions)
...@@ -779,6 +924,9 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h ...@@ -779,6 +924,9 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h
case WM_DDE_POKE: case WM_DDE_POKE:
qs = WDML_HandlePokeReply(pConv, msg, pXAct); qs = WDML_HandlePokeReply(pConv, msg, pXAct);
break; break;
case WM_DDE_TERMINATE:
qs = WDML_HandleTerminateReply(pConv, msg, pXAct);
break;
default: default:
qs = WDML_QS_ERROR; qs = WDML_QS_ERROR;
FIXME("oooch\n"); FIXME("oooch\n");
...@@ -793,6 +941,7 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h ...@@ -793,6 +941,7 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h
switch (qs) switch (qs)
{ {
case WDML_QS_ERROR: case WDML_QS_ERROR:
case WDML_QS_SWALLOWED:
*hdd = 0; *hdd = 0;
break; break;
case WDML_QS_HANDLED: case WDML_QS_HANDLED:
...@@ -800,39 +949,34 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h ...@@ -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 * notify callback if asynchronous, and remove it in any case
*/ */
WDML_UnQueueTransaction(pConv, pXAct); 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() */) WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt,
{ (HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
TRACE("Calling the callback, type = XTYP_XACT_COMPLETE, CB = 0x%lx, hConv = 0x%lx\n", pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */);
(DWORD)pConv->thisInstance->callback, (DWORD)pConv); qs = WDML_QS_PASS;
(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;
}
} }
else else
{ {
*hdd = pXAct->hDdeData; *hdd = pXAct->hDdeData;
} }
WDML_FreeTransaction(pXAct); WDML_FreeTransaction(pConv->instance, pXAct, FALSE); /* FIXME: should we free intermediate pmts ? */
break; break;
case WDML_QS_PASS: case WDML_QS_PASS:
/* no pending transaction found, try a warm link or a termination request */ /* no pending transaction found, try a warm link or a termination request */
switch (msg->message) switch (msg->message)
{ {
case WM_DDE_DATA: case WM_DDE_DATA:
qs = WDML_HandleReplyData(pConv, msg, hdd); qs = WDML_HandleIncomingData(pConv, msg, hdd);
break; break;
case WM_DDE_TERMINATE: case WM_DDE_TERMINATE:
qs = WDML_HandleReplyTerminate(pConv, msg, hdd); qs = WDML_HandleIncomingTerminate(pConv, msg, hdd);
break; break;
} }
break; break;
case WDML_QS_BLOCK:
FIXME("shouldn't be used on client side\n");
break;
} }
return qs; return qs;
...@@ -846,7 +990,9 @@ static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* h ...@@ -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) 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); TRACE("Starting wait for a timeout of %ld ms\n", dwTimeout);
...@@ -855,21 +1001,23 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML ...@@ -855,21 +1001,23 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML
while ((dwTime = GetCurrentTime()) < dwTimeout) 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 * single process they need to share the access to the internal data
*/ */
if (MsgWaitForMultipleObjects(0, NULL, FALSE, if (MsgWaitForMultipleObjects(0, NULL, FALSE,
dwTime - dwTimeout, QS_POSTMESSAGE) == WAIT_OBJECT_0 && dwTime - dwTimeout, QS_POSTMESSAGE) == WAIT_OBJECT_0)
WDML_WaitForMutex(handle_mutex))
{ {
BOOL ret = FALSE; BOOL ret = FALSE;
MSG msg; MSG msg;
WDML_CONV* pConv; WDML_CONV* pConv;
HDDEDATA hdd; HDDEDATA hdd;
pConv = WDML_GetConv(hConv); EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv == NULL) if (pConv == NULL)
{ {
LeaveCriticalSection(&WDML_CritSect);
/* conversation no longer available... return failure */ /* conversation no longer available... return failure */
break; break;
} }
...@@ -881,7 +1029,7 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML ...@@ -881,7 +1029,7 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML
(pConv->transactions == NULL || ret); (pConv->transactions == NULL || ret);
if (ret) break; if (ret) break;
} }
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); LeaveCriticalSection(&WDML_CritSect);
if (ret) if (ret)
{ {
return hdd; return hdd;
...@@ -890,29 +1038,29 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML ...@@ -890,29 +1038,29 @@ static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML
} }
TRACE("Timeout !!\n"); TRACE("Timeout !!\n");
if (WDML_WaitForMutex(handle_mutex))
{
DWORD err;
WDML_CONV* pConv;
pConv = WDML_GetConv(hConv); EnterCriticalSection(&WDML_CritSect);
if (pConv == NULL)
{ pConv = WDML_GetConv(hConv, FALSE);
return 0; if (pConv != NULL)
} {
switch (pConv->transactions->ddeMsg) if (pConv->transactions)
{ {
case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break; switch (pConv->transactions->ddeMsg)
case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break; {
case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break; case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break;
case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break; case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break;
case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break; case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break;
default: err = DMLERR_INVALIDPARAMETER; 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; pConv->instance->lastError = err;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); }
} }
LeaveCriticalSection(&WDML_CritSect);
return 0; return 0;
} }
...@@ -926,9 +1074,8 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS ...@@ -926,9 +1074,8 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
WDML_XACT* pXAct; WDML_XACT* pXAct;
HDDEDATA hDdeData = 0; HDDEDATA hDdeData = 0;
TRACE("(0x%lx,%ld,0x%lx,0x%lx,%d,%d,%ld,0x%lx)\n", TRACE("(%p,%ld,0x%lx,0x%x,%d,%d,%ld,%p)\n",
(ULONG)pData,cbData,(DWORD)hConv,(DWORD)hszItem,wFmt,wType, pData, cbData, (DWORD)hConv, hszItem, wFmt, wType, dwTimeout, pdwResult);
dwTimeout,(ULONG)pdwResult);
if (hConv == 0) if (hConv == 0)
{ {
...@@ -936,12 +1083,9 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS ...@@ -936,12 +1083,9 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
return 0; return 0;
} }
if (!WDML_WaitForMutex(handle_mutex)) EnterCriticalSection(&WDML_CritSect);
{
return FALSE;
}
pConv = WDML_GetConv(hConv); pConv = WDML_GetConv(hConv, TRUE);
if (pConv == NULL) if (pConv == NULL)
{ {
/* cannot set error... cannot get back to DDE instance */ /* cannot set error... cannot get back to DDE instance */
...@@ -953,13 +1097,13 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS ...@@ -953,13 +1097,13 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
case XTYP_EXECUTE: case XTYP_EXECUTE:
if (hszItem != 0 || wFmt != 0) if (hszItem != 0 || wFmt != 0)
{ {
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER; pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError; goto theError;
} }
pXAct = WDML_QueueExecute(pConv, pData, cbData); pXAct = WDML_ClientQueueExecute(pConv, pData, cbData);
break; break;
case XTYP_POKE: case XTYP_POKE:
pXAct = WDML_QueuePoke(pConv, pData, cbData, wFmt, hszItem); pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem);
break; break;
case XTYP_ADVSTART|XTYPF_NODATA: case XTYP_ADVSTART|XTYPF_NODATA:
case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ: case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ:
...@@ -967,34 +1111,52 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS ...@@ -967,34 +1111,52 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
case XTYP_ADVSTART|XTYPF_ACKREQ: case XTYP_ADVSTART|XTYPF_ACKREQ:
if (pData) if (pData)
{ {
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER; pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError; goto theError;
} }
pXAct = WDML_QueueAdvise(pConv, wType, wFmt, hszItem); pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem);
break; break;
case XTYP_ADVSTOP: case XTYP_ADVSTOP:
if (pData) if (pData)
{ {
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER; pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError; goto theError;
} }
pXAct = WDML_QueueUnadvise(pConv, wFmt, hszItem); pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem);
break; break;
case XTYP_REQUEST: case XTYP_REQUEST:
if (pData) if (pData)
{ {
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER; pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError; goto theError;
} }
pXAct = WDML_QueueRequest(pConv, wFmt, hszItem); pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem);
break; break;
default: default:
FIXME("Unknown transation\n"); FIXME("Unknown transation\n");
/* unknown transaction type */ /* unknown transaction type */
pConv->thisInstance->lastError = DMLERR_INVALIDPARAMETER; pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError; 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; pXAct->dwTimeout = dwTimeout;
/* FIXME: should set the app bits on *pdwResult */ /* FIXME: should set the app bits on *pdwResult */
...@@ -1005,27 +1167,27 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS ...@@ -1005,27 +1167,27 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS
*pdwResult = MAKELONG(0, pXAct->xActID); *pdwResult = MAKELONG(0, pXAct->xActID);
} }
hDdeData = (HDDEDATA)1; hDdeData = (HDDEDATA)1;
} }
else
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE);
if (dwTimeout != TIMEOUT_ASYNC)
{ {
DWORD count = 0; DWORD count, i;
if (pdwResult) if (pdwResult)
{ {
*pdwResult = 0L; *pdwResult = 0L;
} }
while (ReleaseMutex(handle_mutex)) count = WDML_CritSect.RecursionCount;
count++; for (i = 0; i < count; i++)
LeaveCriticalSection(&WDML_CritSect);
hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct); hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct);
while (count-- != 0) for (i = 0; i < count; i++)
WDML_WaitForMutex(handle_mutex); EnterCriticalSection(&WDML_CritSect);
} }
LeaveCriticalSection(&WDML_CritSect);
return hDdeData; return hDdeData;
theError: theError:
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); LeaveCriticalSection(&WDML_CritSect);
return 0; return 0;
} }
...@@ -1036,29 +1198,65 @@ HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HS ...@@ -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) 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 && if (iMsg == WM_DDE_ACK &&
/* In response to WM_DDE_INITIATE, save server window */ UnpackDDElParam(WM_DDE_ACK, lParam, &uiLo, &uiHi) &&
UnpackDDElParam(WM_DDE_ACK, lParam, &uiLow, &uiHi) && /* in the initial WM_INITIATE sendmessage */
(WDML_CONV*)GetWindowLongA(hwnd, 4) == NULL) ((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1))
{ {
WDML_INSTANCE* thisInstance = NULL; /* In response to WM_DDE_INITIATE, save server window */
WDML_CONV* pConv = NULL; char buf[256];
WDML_INSTANCE* pInstance;
FreeDDElParam(WM_DDE_ACK, lParam); FreeDDElParam(WM_DDE_ACK, lParam);
/* no converstation yet, add it */
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwnd, 0); /* FIXME: convlist should be handled here */
pConv = WDML_AddConv(thisInstance, WDML_CLIENT_SIDE, (HSZ)uiLow, (HSZ)uiHi, 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); hwnd, (HWND)wParam);
SetWindowLongA(hwnd, 4, (DWORD)pConv);
/* FIXME: so far we only use the first window in the list... */ SetWindowLongA(hwnd, GWL_WDML_CONVERSATION, (DWORD)pConv);
return 0; 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) if (pConv)
{ {
...@@ -1073,14 +1271,14 @@ static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPA ...@@ -1073,14 +1271,14 @@ static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPA
WDML_HandleReply(pConv, &msg, &hdd); WDML_HandleReply(pConv, &msg, &hdd);
} }
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); LeaveCriticalSection(&WDML_CritSect);
return 0; return 0;
} }
return DefWindowProcA(hwnd, iMsg, wParam, lParam); return (IsWindowUnicode(hwnd)) ?
DefWindowProcA(hwnd, iMsg, wParam, lParam) : DefWindowProcW(hwnd, iMsg, wParam, lParam);
} }
/***************************************************************** /*****************************************************************
* DdeAbandonTransaction (USER32.@) * DdeAbandonTransaction (USER32.@)
*/ */
...@@ -1090,6 +1288,57 @@ BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction ...@@ -1090,6 +1288,57 @@ BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction
return TRUE; 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.@) * DdeImpersonateClient (USER32.@)
...@@ -1099,15 +1348,12 @@ BOOL WINAPI DdeImpersonateClient(HCONV hConv) ...@@ -1099,15 +1348,12 @@ BOOL WINAPI DdeImpersonateClient(HCONV hConv)
WDML_CONV* pConv; WDML_CONV* pConv;
BOOL ret = FALSE; BOOL ret = FALSE;
if (!WDML_WaitForMutex(handle_mutex)) EnterCriticalSection(&WDML_CritSect);
{ pConv = WDML_GetConv(hConv, TRUE);
return FALSE;
}
pConv = WDML_GetConv(hConv);
if (pConv) if (pConv)
{ {
ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer); ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer);
} }
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); LeaveCriticalSection(&WDML_CritSect);
return ret; return ret;
} }
...@@ -15,27 +15,17 @@ ...@@ -15,27 +15,17 @@
/* defined in atom.c file. /* defined in atom.c file.
*/ */
#define MAX_ATOM_LEN 255 #define MAX_ATOM_LEN 255
/* Maximum buffer size ( including the '\0' ). /* Maximum buffer size ( including the '\0' ).
*/ */
#define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1) #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: /* The internal structures (prefixed by WDML) are used as follows:
* + a WDML_INSTANCE is created for each instance creation (DdeInitialize) * + a WDML_INSTANCE is created for each instance creation (DdeInitialize)
* - a popup windows (InstanceClass) is created for each instance. It will be * - a popup window (InstanceClass) is created for each instance.
* used to receive all the DDEML events (server registration, conversation * - this window is used to receive all the DDEML events (server registration,
* confirmation...) * conversation confirmation...). See the WM_WDML_???? messages for details
* + when registring a server (DdeNameService) a WDML_SERVER is created * + when registring a server (DdeNameService) a WDML_SERVER is created
* - a popup window (ServerNameClass) is created * - a popup window (ServerNameClass) is created
* + a conversation is represented by two WDML_CONV structures: * + a conversation is represented by two WDML_CONV structures:
...@@ -47,6 +37,13 @@ ...@@ -47,6 +37,13 @@
* o a child window (of the ServerName) on the server side * o a child window (of the ServerName) on the server side
* (ServerConvClass) * (ServerConvClass)
* - all the exchanges then take place between those two windows * - 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: * + a (warm or link) is represented by two WDML_LINK structures:
* - one on client side, the other one on server side * - one on client side, the other one on server side
* - therefore, two lists of links are kept for each instance * - therefore, two lists of links are kept for each instance
...@@ -55,67 +52,77 @@ ...@@ -55,67 +52,77 @@
* - offset 0: the DDE instance * - offset 0: the DDE instance
* - offset 4: the current conversation (for ClientConv and ServerConv only) * - 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 typedef struct tagHSZNode
{ {
struct tagHSZNode* next; struct tagHSZNode* next;
HSZ hsz; HSZ hsz;
HSZ hsz2; unsigned refCount;
} HSZNode; } HSZNode;
typedef struct tagWDML_SERVER typedef struct tagWDML_SERVER
{ {
struct tagWDML_SERVER* next; struct tagWDML_SERVER* next;
HSZ hszService; HSZ hszService;
HSZ hszTopic; HSZ hszServiceSpec;
ATOM atomService;
ATOM atomServiceSpec;
BOOL filterOn; BOOL filterOn;
HWND hwndServer; HWND hwndServer;
} WDML_SERVER; } WDML_SERVER;
typedef struct tagWDML_XACT { typedef struct tagWDML_XACT {
struct tagWDML_XACT* next; struct tagWDML_XACT* next; /* list of transactions in conversation */
DWORD xActID; DWORD xActID;
UINT ddeMsg; UINT ddeMsg;
HDDEDATA hDdeData; HDDEDATA hDdeData;
DWORD dwTimeout; DWORD dwTimeout;
DWORD hUser; DWORD hUser;
union { UINT wType;
struct { UINT wFmt;
UINT wType; HSZ hszItem;
UINT wFmt; ATOM atom; /* as converted from or to hszItem */
HSZ hszItem; HGLOBAL hMem;
HGLOBAL hDdeAdvise; LPARAM lParam; /* useful for reusing */
} advise;
struct {
UINT wFmt;
HSZ hszItem;
} unadvise;
struct {
HGLOBAL hMem;
} execute;
struct {
HGLOBAL hMem;
HSZ hszItem;
} poke;
struct {
HSZ hszItem;
} request;
} u;
} WDML_XACT; } WDML_XACT;
typedef struct tagWDML_CONV typedef struct tagWDML_CONV
{ {
struct tagWDML_CONV* next; /* to link all the conversations */ struct tagWDML_CONV* next; /* to link all the conversations */
struct tagWDML_INSTANCE* thisInstance; struct tagWDML_INSTANCE* instance;
HSZ hszService; /* pmt used for connection */ HSZ hszService; /* pmt used for connection */
HSZ hszTopic; /* pmt used for connection */ HSZ hszTopic; /* pmt used for connection */
UINT afCmd; /* service name flag */ UINT afCmd; /* service name flag */
CONVCONTEXT convContext; CONVCONTEXT convContext;
HWND hwndClient; /* source of conversation (ClientConvClass) */ HWND hwndClient; /* source of conversation (ClientConvClass) */
HWND hwndServer; /* destination of conversation (ServerConvClass) */ HWND hwndServer; /* destination of conversation (ServerConvClass) */
WDML_XACT* transactions; /* pending transactions (client only) */ WDML_XACT* transactions; /* pending transactions */
DWORD hUser; /* user defined value */ DWORD hUser; /* user defined value */
DWORD wStatus; /* same bits as convinfo.wStatus */
DWORD wConvst; /* same values as convinfo.wConvst */
} WDML_CONV; } WDML_CONV;
/* DDE_LINK struct defines hot, warm, and cold links */ /* DDE_LINK struct defines hot, warm, and cold links */
...@@ -132,6 +139,7 @@ typedef struct tagWDML_INSTANCE ...@@ -132,6 +139,7 @@ typedef struct tagWDML_INSTANCE
{ {
struct tagWDML_INSTANCE* next; struct tagWDML_INSTANCE* next;
DWORD instanceID; /* needed to track monitor usage */ 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 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 clientOnly; /* bit wasteful of space but it will be faster */
BOOL unicode; /* Flag to indicate Win32 API used to initialise */ BOOL unicode; /* Flag to indicate Win32 API used to initialise */
...@@ -140,7 +148,6 @@ typedef struct tagWDML_INSTANCE ...@@ -140,7 +148,6 @@ typedef struct tagWDML_INSTANCE
PFNCALLBACK callback; PFNCALLBACK callback;
DWORD CBFflags; DWORD CBFflags;
DWORD monitorFlags; DWORD monitorFlags;
UINT txnCount; /* count transactions open to simplify closure */
DWORD lastError; DWORD lastError;
HWND hwndEvent; HWND hwndEvent;
WDML_SERVER* servers; /* list of registered servers */ WDML_SERVER* servers; /* list of registered servers */
...@@ -148,9 +155,7 @@ typedef struct tagWDML_INSTANCE ...@@ -148,9 +155,7 @@ typedef struct tagWDML_INSTANCE
WDML_LINK* links[2]; /* active links for this instance (client and server) */ WDML_LINK* links[2]; /* active links for this instance (client and server) */
} WDML_INSTANCE; } WDML_INSTANCE;
extern WDML_INSTANCE* WDML_InstanceList; /* list of created instances, a process can create many */ extern CRITICAL_SECTION WDML_CritSect; /* protection for instance list */
extern DWORD WDML_MaxInstanceID; /* FIXME: OK for present, may have to worry about wrap-around later */
extern HANDLE handle_mutex;
/* header for the DDE Data objects */ /* header for the DDE Data objects */
typedef struct tagDDE_DATAHANDLE_HEAD typedef struct tagDDE_DATAHANDLE_HEAD
...@@ -163,46 +168,80 @@ typedef enum tagWDML_SIDE ...@@ -163,46 +168,80 @@ typedef enum tagWDML_SIDE
WDML_CLIENT_SIDE = 0, WDML_SERVER_SIDE = 1 WDML_CLIENT_SIDE = 0, WDML_SERVER_SIDE = 1
} WDML_SIDE; } WDML_SIDE;
/* server calls this. */ typedef enum {
extern WDML_SERVER* WDML_AddServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic); WDML_QS_ERROR, WDML_QS_HANDLED, WDML_QS_PASS, WDML_QS_SWALLOWED, WDML_QS_BLOCK,
extern void WDML_RemoveServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic); } WDML_QUEUE_STATE;
extern WDML_SERVER* WDML_FindServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic);
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. */ /* 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); HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer);
extern void WDML_RemoveConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, HCONV hConv); extern void WDML_RemoveConv(WDML_CONV* pConv, WDML_SIDE side);
extern WDML_CONV* WDML_GetConv(HCONV hConv); extern WDML_CONV* WDML_GetConv(HCONV hConv, BOOL checkConnected);
extern WDML_CONV* WDML_FindConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, extern WDML_CONV* WDML_GetConvFromWnd(HWND hWnd);
extern WDML_CONV* WDML_FindConv(WDML_INSTANCE* pInstance, WDML_SIDE side,
HSZ hszService, HSZ hszTopic); 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); 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); 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); 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 */ /* 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 void WDML_QueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct);
extern BOOL WDML_UnQueueTransaction(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 WDML_XACT* WDML_FindTransaction(WDML_CONV* pConv, DWORD tid);
extern HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease, extern HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease,
BOOL fDeferUpd, BOOL dAckReq); BOOL fDeferUpd, BOOL dAckReq);
extern HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem); extern HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem, WINE_DDEHEAD* da);
extern WDML_INSTANCE* WDML_FindInstance(DWORD InstId); extern WDML_INSTANCE* WDML_GetInstance(DWORD InstId);
extern BOOL WDML_WaitForMutex(HANDLE mutex); extern WDML_INSTANCE* WDML_GetInstanceFromWnd(HWND hWnd);
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);
/* broadcasting to DDE windows */ /* broadcasting to DDE windows */
extern void WDML_BroadcastDDEWindows(const char* clsName, UINT uMsg, extern void WDML_BroadcastDDEWindows(const char* clsName, UINT uMsg,
WPARAM wParam, LPARAM lParam); 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_REGISTER (WM_USER + 0x200)
#define WM_WDML_UNREGISTER (WM_USER + 0x201) #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 */ #endif /* __WINE_DDEML_PRIVATE_H */
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "winerror.h" #include "winerror.h"
#include "dde.h" #include "dde.h"
#include "ddeml.h" #include "ddeml.h"
#include "dde/dde_private.h"
#include "debugtools.h" #include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(ddeml); DEFAULT_DEBUG_CHANNEL(ddeml);
...@@ -54,6 +55,22 @@ typedef struct ...@@ -54,6 +55,22 @@ typedef struct
CONVCONTEXT16 ConvCtxt; CONVCONTEXT16 ConvCtxt;
} CONVINFO16, *LPCONVINFO16; } 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) * DdeInitialize (DDEML.2)
...@@ -61,8 +78,7 @@ typedef struct ...@@ -61,8 +78,7 @@ typedef struct
UINT16 WINAPI DdeInitialize16(LPDWORD pidInst, PFNCALLBACK16 pfnCallback, UINT16 WINAPI DdeInitialize16(LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
DWORD afCmd, DWORD ulRes) DWORD afCmd, DWORD ulRes)
{ {
return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback, return WDML_Initialize(pidInst, (PFNCALLBACK)pfnCallback, afCmd, ulRes, FALSE, TRUE);
afCmd, ulRes);
} }
/***************************************************************** /*****************************************************************
...@@ -145,8 +161,7 @@ BOOL16 WINAPI DdeDisconnect16(HCONV hConv) ...@@ -145,8 +161,7 @@ BOOL16 WINAPI DdeDisconnect16(HCONV hConv)
*/ */
BOOL16 WINAPI DdeSetUserHandle16(HCONV hConv, DWORD id, DWORD hUser) BOOL16 WINAPI DdeSetUserHandle16(HCONV hConv, DWORD id, DWORD hUser)
{ {
FIXME("(%d,%ld,%ld): stub\n",hConv,id, hUser); return DdeSetUserHandle(hConv, id, hUser);
return 0;
} }
/***************************************************************** /*****************************************************************
...@@ -167,7 +182,9 @@ HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage) ...@@ -167,7 +182,9 @@ HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage)
if (codepage) if (codepage)
{ {
return DdeCreateStringHandleA(idInst, str, codepage); return DdeCreateStringHandleA(idInst, str, codepage);
} else { }
else
{
TRACE("Default codepage supplied\n"); TRACE("Default codepage supplied\n");
return DdeCreateStringHandleA(idInst, str, CP_WINANSI); return DdeCreateStringHandleA(idInst, str, CP_WINANSI);
} }
...@@ -178,7 +195,7 @@ HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage) ...@@ -178,7 +195,7 @@ HSZ WINAPI DdeCreateStringHandle16(DWORD idInst, LPCSTR str, INT16 codepage)
*/ */
BOOL16 WINAPI DdeFreeStringHandle16(DWORD idInst, HSZ hsz) 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); return (BOOL)DdeFreeStringHandle(idInst, hsz);
} }
...@@ -218,8 +235,7 @@ HDDEDATA WINAPI DdeClientTransaction16(LPVOID pData, DWORD cbData, ...@@ -218,8 +235,7 @@ HDDEDATA WINAPI DdeClientTransaction16(LPVOID pData, DWORD cbData,
BOOL16 WINAPI DdeAbandonTransaction16(DWORD idInst, HCONV hConv, BOOL16 WINAPI DdeAbandonTransaction16(DWORD idInst, HCONV hConv,
DWORD idTransaction) DWORD idTransaction)
{ {
FIXME("empty stub\n"); return DdeAbandonTransaction(idInst, hConv, idTransaction);
return TRUE;
} }
/***************************************************************** /*****************************************************************
...@@ -256,7 +272,8 @@ DWORD WINAPI DdeGetData16( ...@@ -256,7 +272,8 @@ DWORD WINAPI DdeGetData16(
*/ */
LPBYTE WINAPI DdeAccessData16(HDDEDATA hData, LPDWORD pcbDataSize) 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) ...@@ -264,7 +281,7 @@ LPBYTE WINAPI DdeAccessData16(HDDEDATA hData, LPDWORD pcbDataSize)
*/ */
BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData) BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData)
{ {
return DdeUnaccessData(hData); return DdeUnaccessData(hData);
} }
/***************************************************************** /*****************************************************************
...@@ -272,7 +289,7 @@ BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData) ...@@ -272,7 +289,7 @@ BOOL16 WINAPI DdeUnaccessData16(HDDEDATA hData)
*/ */
BOOL16 WINAPI DdeEnableCallback16(DWORD idInst, HCONV hConv, UINT16 wCmd) 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) ...@@ -281,7 +298,7 @@ BOOL16 WINAPI DdeEnableCallback16(DWORD idInst, HCONV hConv, UINT16 wCmd)
HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2, HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2,
UINT16 afCmd) 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, ...@@ -289,7 +306,7 @@ HDDEDATA WINAPI DdeNameService16(DWORD idInst, HSZ hsz1, HSZ hsz2,
*/ */
UINT16 WINAPI DdeGetLastError16(DWORD idInst) UINT16 WINAPI DdeGetLastError16(DWORD idInst)
{ {
return (UINT16)DdeGetLastError(idInst); return (UINT16)DdeGetLastError(idInst);
} }
/***************************************************************** /*****************************************************************
...@@ -297,7 +314,7 @@ UINT16 WINAPI DdeGetLastError16(DWORD idInst) ...@@ -297,7 +314,7 @@ UINT16 WINAPI DdeGetLastError16(DWORD idInst)
*/ */
INT16 WINAPI DdeCmpStringHandles16(HSZ hsz1, HSZ hsz2) INT16 WINAPI DdeCmpStringHandles16(HSZ hsz1, HSZ hsz2)
{ {
return DdeCmpStringHandles(hsz1, hsz2); return DdeCmpStringHandles(hsz1, hsz2);
} }
/****************************************************************** /******************************************************************
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <string.h> #include <string.h>
#include <stdio.h>
#include "winbase.h" #include "winbase.h"
#include "windef.h" #include "windef.h"
#include "wingdi.h" #include "wingdi.h"
...@@ -23,18 +24,16 @@ ...@@ -23,18 +24,16 @@
DEFAULT_DEBUG_CHANNEL(ddeml); DEFAULT_DEBUG_CHANNEL(ddeml);
WDML_INSTANCE* WDML_InstanceList = NULL; static WDML_INSTANCE* WDML_InstanceList = NULL;
DWORD WDML_MaxInstanceID = 0; /* OK for present, may have to worry about wrap-around later */ static DWORD WDML_MaxInstanceID = 0; /* OK for present, have to worry about wrap-around later */
static const char DDEInstanceAccess[] = "DDEMaxInstance";
static const char DDEHandleAccess[] = "DDEHandleAccess";
HANDLE handle_mutex = 0;
const char WDML_szEventClass[] = "DdeEventClass"; 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 * Pure DDE (non DDEML) management
* but would do with the simple DWORD for lParam *
*/ * ================================================================ */
static BOOL DDE_RequirePacking(UINT msg) static BOOL DDE_RequirePacking(UINT msg)
{ {
...@@ -218,11 +217,11 @@ LPARAM WINAPI ReuseDDElParam(LPARAM lParam, UINT msgIn, UINT msgOut, ...@@ -218,11 +217,11 @@ LPARAM WINAPI ReuseDDElParam(LPARAM lParam, UINT msgIn, UINT msgOut,
/***************************************************************** /*****************************************************************
* ImpersonateDdeClientWindow (USER32.@) * ImpersonateDdeClientWindow (USER32.@)
* *
* PARAMS
* hWndClient [I] handle to DDE client window
* hWndServer [I] handle to DDE server window
*/ */
BOOL WINAPI ImpersonateDdeClientWindow( BOOL WINAPI ImpersonateDdeClientWindow(HWND hWndClient, HWND hWndServer)
HWND hWndClient, /* [in] handle to DDE client window */
HWND hWndServer /* [in] handle to DDE server window */
)
{ {
FIXME("(%04x %04x): stub\n", hWndClient, hWndServer); FIXME("(%04x %04x): stub\n", hWndClient, hWndServer);
return FALSE; return FALSE;
...@@ -239,188 +238,153 @@ BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, CONST SECURITY_QUALITY_OF_SE ...@@ -239,188 +238,153 @@ BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, CONST SECURITY_QUALITY_OF_SE
return TRUE; return TRUE;
} }
/* ================================================================
*
* Instance management
*
* ================================================================ */
/****************************************************************************** /******************************************************************************
* IncrementInstanceId * IncrementInstanceId
* *
* generic routine to increment the max instance Id and allocate a new application instance * 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); DWORD id = InterlockedIncrement(&WDML_MaxInstanceID);
thisInstance->instanceID = id; pInstance->instanceID = id;
TRACE("New instance id %ld allocated\n", 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) static LRESULT CALLBACK WDML_EventProc(HWND hwndEvent, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
WDML_INSTANCE* thisInstance; WDML_INSTANCE* pInstance;
HDDEDATA hDdeData; HSZ hsz1, hsz2;
switch (uMsg) switch (uMsg)
{ {
case WM_WDML_REGISTER: case WM_WDML_REGISTER:
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndEvent, 0); pInstance = WDML_GetInstanceFromWnd(hwndEvent);
/* try calling the Callback */ /* 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", hsz1 = WDML_MakeHszFromAtom(pInstance, wParam);
(DWORD)thisInstance->callback); hsz2 = WDML_MakeHszFromAtom(pInstance, lParam);
WDML_InvokeCallback(pInstance, XTYP_REGISTER, 0, 0, hsz1, hsz2, 0, 0, 0);
hDdeData = (thisInstance->callback)(XTYP_REGISTER, 0, 0, WDML_DecHSZ(pInstance, hsz1);
(HSZ)wParam, (HSZ)lParam, 0, 0, 0); WDML_DecHSZ(pInstance, hsz2);
TRACE("Callback function called - result=%d\n", (INT)hDdeData);
} }
break; break;
case WM_WDML_UNREGISTER: case WM_WDML_UNREGISTER:
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndEvent, 0); pInstance = WDML_GetInstanceFromWnd(hwndEvent);
if (pInstance && !(pInstance->CBFflags & CBF_SKIP_UNREGISTRATIONS))
if (thisInstance && thisInstance->callback != NULL) {
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", pConv->wStatus |= ST_ISLOCAL;
thisInstance->instanceID);
(thisInstance->callback)(XTYP_UNREGISTER, 0, 0, WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv,
(HSZ)wParam, (HSZ)lParam, 0, 0, 0); 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.@] * WDML_Initialize
* 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, UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes) DWORD afCmd, DWORD ulRes, BOOL bUnicode, BOOL b16)
{ {
WDML_INSTANCE* pInstance;
/* 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* reference_inst; WDML_INSTANCE* reference_inst;
UINT ret; UINT ret;
WNDCLASSEXA wndclass; WNDCLASSEXA wndclass;
TRACE("(%p,%p,0x%lx,%ld)\n",
pidInst, pfnCallback, afCmd, ulRes);
if (ulRes) if (ulRes)
{ {
ERR("Reserved value not zero? What does this mean?\n"); 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 */ /* trap this and no more until we know more */
return DMLERR_NO_ERROR; 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 /* grab enough heap for one control struct - not really necessary for re-initialise
* but allows us to use same validation routines */ * but allows us to use same validation routines */
thisInstance = (WDML_INSTANCE*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE)); pInstance = (WDML_INSTANCE*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE));
if (thisInstance == NULL) if (pInstance == NULL)
{ {
/* catastrophe !! warn user & abort */ /* catastrophe !! warn user & abort */
ERR("Instance create failed - out of memory\n"); ERR("Instance create failed - out of memory\n");
return DMLERR_SYS_ERROR; return DMLERR_SYS_ERROR;
} }
thisInstance->next = NULL; pInstance->next = NULL;
thisInstance->monitor = (afCmd | APPCLASS_MONITOR); pInstance->monitor = (afCmd | APPCLASS_MONITOR);
/* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */ /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
thisInstance->clientOnly = afCmd & APPCMD_CLIENTONLY; pInstance->clientOnly = afCmd & APPCMD_CLIENTONLY;
thisInstance->instanceID = *pidInst; /* May need to add calling proc Id */ pInstance->instanceID = *pidInst; /* May need to add calling proc Id */
thisInstance->callback = *pfnCallback; pInstance->threadID = GetCurrentThreadId();
thisInstance->txnCount = 0; pInstance->callback = *pfnCallback;
thisInstance->unicode = TRUE; pInstance->unicode = bUnicode;
thisInstance->win16 = FALSE; pInstance->win16 = b16;
thisInstance->nodeList = NULL; /* node will be added later */ pInstance->nodeList = NULL; /* node will be added later */
thisInstance->monitorFlags = afCmd & MF_MASK; pInstance->monitorFlags = afCmd & MF_MASK;
thisInstance->servers = NULL; pInstance->servers = NULL;
thisInstance->convs[0] = NULL; pInstance->convs[0] = NULL;
thisInstance->convs[1] = NULL; pInstance->convs[1] = NULL;
thisInstance->links[0] = NULL; pInstance->links[0] = NULL;
thisInstance->links[1] = NULL; pInstance->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);
/* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */ /* 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 !! */ /* Check for other way of setting Client-only !! */
thisInstance->clientOnly = pInstance->clientOnly =
(thisInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS; (pInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS;
} }
TRACE("instance created - checking validity \n"); TRACE("instance created - checking validity \n");
...@@ -429,30 +393,13 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, ...@@ -429,30 +393,13 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
{ {
/* Initialisation of new Instance Identifier */ /* Initialisation of new Instance Identifier */
TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd); TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
if (WDML_MaxInstanceID == 0)
{ EnterCriticalSection(&WDML_CritSect);
/* 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;
}
if (WDML_InstanceList == NULL) if (WDML_InstanceList == NULL)
{ {
/* can't be another instance in this case, assign to the base pointer */ /* 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 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
* present * present
...@@ -463,11 +410,10 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, ...@@ -463,11 +410,10 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
* first call for a given callback !!! * 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"); TRACE("First application instance detected OK\n");
/* allocate new instance ID */ /* allocate new instance ID */
if ((err_no = WDML_IncrementInstanceId(thisInstance))) return err_no; WDML_IncrementInstanceId(pInstance);
} }
else else
{ {
...@@ -484,27 +430,27 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, ...@@ -484,27 +430,27 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
* clever (lazy ?) it will fail to pick up that later calls are for * clever (lazy ?) it will fail to pick up that later calls are for
* the same application - should we trust them ? * 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; ret = DMLERR_DLL_USAGE;
goto theError; 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; ret = DMLERR_INVALIDPARAMETER;
goto theError; 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; ret = DMLERR_DLL_USAGE;
goto theError; goto theError;
...@@ -515,30 +461,50 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, ...@@ -515,30 +461,50 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
/* All cleared, add to chain */ /* All cleared, add to chain */
TRACE("Application Instance checks finished\n"); TRACE("Application Instance checks finished\n");
if ((err_no = WDML_IncrementInstanceId(thisInstance))) return err_no; WDML_IncrementInstanceId(pInstance);
reference_inst->next = thisInstance; reference_inst->next = pInstance;
} }
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return DMLERR_SYS_ERROR; LeaveCriticalSection(&WDML_CritSect);
*pidInst = thisInstance->instanceID;
*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"); TRACE("New application instance processing finished OK\n");
} }
else else
{ {
/* Reinitialisation situation --- FIX */ /* 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)) EnterCriticalSection(&WDML_CritSect);
{
HeapFree(GetProcessHeap(), 0, thisInstance);
return DMLERR_SYS_ERROR;
}
if (WDML_InstanceList == NULL) if (WDML_InstanceList == NULL)
{ {
ret = DMLERR_DLL_USAGE; ret = DMLERR_DLL_USAGE;
goto theError; 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 !! */ /* can't reinitialise if we have initialised nothing !! */
reference_inst = WDML_InstanceList; reference_inst = WDML_InstanceList;
/* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */ /* 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, ...@@ -567,7 +533,7 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
} }
/* Check 2 - cannot change monitor modes */ /* Check 2 - cannot change monitor modes */
if (thisInstance->monitor != reference_inst->monitor) if (pInstance->monitor != reference_inst->monitor)
{ {
ret = DMLERR_DLL_USAGE; ret = DMLERR_DLL_USAGE;
goto theError; goto theError;
...@@ -593,26 +559,50 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, ...@@ -593,26 +559,50 @@ UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
ret = DMLERR_INVALIDPARAMETER; ret = DMLERR_INVALIDPARAMETER;
goto theError; goto theError;
} }
/* All checked - change relevant flags */ /* All checked - change relevant flags */
reference_inst->CBFflags = thisInstance->CBFflags; reference_inst->CBFflags = pInstance->CBFflags;
reference_inst->clientOnly = thisInstance->clientOnly; reference_inst->clientOnly = pInstance->clientOnly;
reference_inst->monitorFlags = thisInstance->monitorFlags; reference_inst->monitorFlags = pInstance->monitorFlags;
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) LeaveCriticalSection(&WDML_CritSect);
{
HeapFree(GetProcessHeap(), 0, thisInstance);
return DMLERR_SYS_ERROR;
}
} }
return DMLERR_NO_ERROR; return DMLERR_NO_ERROR;
theError: theError:
HeapFree(GetProcessHeap(), 0, thisInstance); HeapFree(GetProcessHeap(), 0, pInstance);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", 0)) LeaveCriticalSection(&WDML_CritSect);
return DMLERR_SYS_ERROR;
return ret; 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 * DdeUninitialize [USER32.@] Frees DDEML resources
* *
...@@ -628,386 +618,408 @@ BOOL WINAPI DdeUninitialize(DWORD idInst) ...@@ -628,386 +618,408 @@ BOOL WINAPI DdeUninitialize(DWORD idInst)
{ {
/* Stage one - check if we have a handle for this instance /* Stage one - check if we have a handle for this instance
*/ */
WDML_INSTANCE* thisInstance; WDML_INSTANCE* pInstance;
WDML_INSTANCE* reference_inst; 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 /* First check instance
*/ */
thisInstance = WDML_FindInstance(idInst); pInstance = WDML_GetInstance(idInst);
if (thisInstance == NULL) 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 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/ */
return FALSE; return FALSE;
} }
FIXME("(%ld): partial stub\n", idInst);
/* first terminate all conversations client side
/* FIXME ++++++++++++++++++++++++++++++++++++++++++ * this shall close existing links...
* Needs to de-register all service names
*
*/ */
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 /* Free the nodes that were not freed by this instance
* and remove the nodes from the list of HSZ nodes. * 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 */ /* OK now delete the instance handle itself */
if (WDML_InstanceList == thisInstance) if (WDML_InstanceList == pInstance)
{ {
/* special case - the first/only entry /* special case - the first/only entry
*/ */
WDML_InstanceList = thisInstance->next; WDML_InstanceList = pInstance->next;
} }
else else
{ {
/* general case /* general case
*/ */
reference_inst = WDML_InstanceList; 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); HeapFree(GetProcessHeap(), 0, pInstance);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) LeaveCriticalSection(&WDML_CritSect);
{
/* should record something here, but nothing left to hang it from !!
*/
return FALSE;
}
return TRUE; 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; WDML_INSTANCE* pInstance;
HSZNode* pCurrent = NULL; WDML_INSTANCE* next;
DWORD tid = GetCurrentThreadId();
/* Set the current node at the start of the list.
*/ EnterCriticalSection(&WDML_CritSect);
pCurrent = thisInstance->nodeList; for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = next)
/* While we have more nodes.
*/
while (pCurrent != NULL)
{ {
/* If we found the node we were looking for. next = pInstance->next;
*/ if (pInstance->threadID == tid)
if (pCurrent->hsz == hsz)
{ {
/* Remove the node. DdeUninitialize(pInstance->instanceID);
*/
/* 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;
} }
/* 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; HDDEDATA ret;
if (hsz != 0) 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 */ ret = WDML_InvokeCallback16(pInstance->callback, uType, uFmt, hConv,
if (thisInstance->unicode) hsz1, hsz2, hdata, dwData1, dwData2);
{
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);
}
}
} }
return hsz2; else
}
/******************************************************************************
* InsertHSZNode (INTERNAL)
*
* Insert a node to the head of the list.
*/
static void WDML_InsertHSZNode(WDML_INSTANCE* thisInstance, HSZ hsz)
{
if (hsz != 0)
{ {
HSZNode* pNew = NULL; ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2);
/* 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");
}
} }
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 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
* for an instance Id, or NULL if the entry does not exist * 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; for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = pInstance->next)
while (thisInstance != NULL)
{ {
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"); TRACE("Instance entry missing\n");
return NULL; 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)) return (WDML_INSTANCE*)GetWindowLongA(hWnd, GWL_WDML_INSTANCE);
{
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;
} }
/****************************************************************************** /******************************************************************************
* 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 */ /* First check instance
if (WAIT_TIMEOUT == result) */
pInstance = WDML_GetInstance(idInst);
if (pInstance == NULL)
{ {
ERR("WaitForSingleObject timed out\n"); error_code = DMLERR_DLL_NOT_INITIALIZED;
return FALSE;
} }
else
if (WAIT_FAILED == result)
{ {
ERR("WaitForSingleObject failed - error %li\n", GetLastError()); error_code = pInstance->lastError;
return FALSE; 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]; if (pNode->hsz == hsz) break;
GlobalGetAtomNameW(hsz, SNameBuffer, MAX_BUFFER_LEN);
GlobalAddAtomW(SNameBuffer);
} else {
CHAR SNameBuffer[MAX_BUFFER_LEN];
GlobalGetAtomNameA(hsz, SNameBuffer, MAX_BUFFER_LEN);
GlobalAddAtomA(SNameBuffer);
} }
if (!pNode) WARN("HSZ 0x%x not found\n", hsz);
return pNode;
} }
/******************************************************************
/****************************************************************************** * WDML_MakeAtomFromHsz
* WDML_ReleaseAtom
* *
* 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
*/ */
ATOM WDML_MakeAtomFromHsz(HSZ hsz)
void WDML_ReleaseAtom(WDML_INSTANCE* thisInstance, 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; WCHAR nameBuffer[MAX_BUFFER_LEN];
CHAR pString[MAX_BUFFER_LEN];
WDML_INSTANCE* thisInstance; GlobalGetAtomNameW(atom, nameBuffer, MAX_BUFFER_LEN);
return DdeCreateStringHandleW(pInstance->instanceID, nameBuffer, CP_WINUNICODE);
TRACE("(%ld, 0x%x, %p, %ld, %d): partial stub\n", }
idInst, hsz, psz, cchMax, iCodePage);
/******************************************************************
if (WDML_MaxInstanceID == 0) * WDML_IncHSZ
{ *
/* Nothing has been initialised - exit now ! */ *
/* needs something for DdeGetLAstError even if the manual doesn't say so */ */
return FALSE; BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
} {
HSZNode* pNode;
if (!WDML_WaitForMutex(handle_mutex))
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;
}
} }
WARN("HSZ 0x%xnot found\n", hsz);
/* First check instance
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); while (pInstance->nodeList != NULL)
if (thisInstance == NULL)
{ {
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return FALSE; DdeFreeStringHandle(pInstance->instanceID, pInstance->nodeList->hsz);
/*
Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/
return FALSE;
} }
}
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 HSZNode* pNew = NULL;
* of the string. /* Create a new node for this HSZ.
*/ */
if (psz == NULL) pNew = (HSZNode*)HeapAlloc(GetProcessHeap(), 0, sizeof(HSZNode));
if (pNew != NULL)
{ {
psz = pString; pNew->hsz = hsz;
cchMax = MAX_BUFFER_LEN; 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; return ret;
} }
...@@ -1017,32 +1029,55 @@ DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT ...@@ -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 WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
{ {
DWORD ret = 0; DWORD ret = 0;
WCHAR pString[MAX_BUFFER_LEN]; WDML_INSTANCE* pInstance;
int factor = 1;
TRACE("(%ld, 0x%x, %p, %ld, %d)\n",
TRACE("(%ld, 0x%x, %p, %ld, %d): partial-stub\n",
idInst, hsz, psz, cchMax, iCodePage); 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 if (iCodePage == 0) iCodePage = CP_WINUNICODE;
* of the string. ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
*/
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;
} }
LeaveCriticalSection(&WDML_CritSect);
TRACE("returning %s\n", debugstr_w(psz));
return ret; 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.@] * DdeCreateStringHandleA [USER32.@]
* *
...@@ -1053,126 +1088,53 @@ DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, IN ...@@ -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 WINAPI DdeCreateStringHandleA(DWORD idInst, LPCSTR psz, INT codepage)
{ {
HSZ hsz = 0; 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) EnterCriticalSection(&WDML_CritSect);
{
/* 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;
}
if (codepage == CP_WINANSI) pInstance = WDML_GetInstance(idInst);
if (pInstance)
{ {
hsz = GlobalAddAtomA(psz); if (codepage == 0) codepage = CP_WINANSI;
/* Save the handle so we know to clean it when hsz = WDML_CreateString(pInstance, psz, codepage);
* 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;
} }
else
{ LeaveCriticalSection(&WDML_CritSect);
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); return hsz;
}
TRACE("Returning error\n");
return 0;
} }
/****************************************************************************** /******************************************************************************
* DdeCreateStringHandleW [USER32.@] Creates handle to identify string * DdeCreateStringHandleW [USER32.@] Creates handle to identify string
* *
* PARAMS
* idInst [I] Instance identifier
* psz [I] Pointer to string
* codepage [I] Code page identifier
* RETURNS * RETURNS
* Success: String handle * Success: String handle
* Failure: 0 * Failure: 0
*/ */
HSZ WINAPI DdeCreateStringHandleW( HSZ WINAPI DdeCreateStringHandleW(DWORD idInst, LPCWSTR psz, INT codepage)
DWORD idInst, /* [in] Instance identifier */
LPCWSTR psz, /* [in] Pointer to string */
INT codepage) /* [in] Code page identifier */
{ {
WDML_INSTANCE* thisInstance; WDML_INSTANCE* pInstance;
HSZ hsz = 0; HSZ hsz = 0;
TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(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;
}
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)
{ {
/* if (codepage == 0) codepage = CP_WINUNICODE;
* Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ? hsz = WDML_CreateString(pInstance, psz, codepage);
*/
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;
} }
else LeaveCriticalSection(&WDML_CritSect);
{
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); return hsz;
}
TRACE("Returning error\n");
return 0;
} }
/***************************************************************** /*****************************************************************
...@@ -1182,45 +1144,22 @@ HSZ WINAPI DdeCreateStringHandleW( ...@@ -1182,45 +1144,22 @@ HSZ WINAPI DdeCreateStringHandleW(
*/ */
BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz) BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz)
{ {
WDML_INSTANCE* thisInstance; WDML_INSTANCE* pInstance;
HSZ hsz2; BOOL ret = FALSE;
TRACE("(%ld,%d): \n",idInst,hsz); TRACE("(%ld,0x%x): \n", idInst, hsz);
if (WDML_MaxInstanceID == 0) EnterCriticalSection(&WDML_CritSect);
{
/* 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 /* First check instance
*/ */
thisInstance = WDML_FindInstance(idInst); pInstance = WDML_GetInstance(idInst);
if ((thisInstance == NULL) || (thisInstance->nodeList == NULL)) if (pInstance)
{ ret = WDML_DecHSZ(pInstance, hsz);
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return TRUE;
/* Nothing has been initialised - exit now ! can return TRUE since effect is the same */ LeaveCriticalSection(&WDML_CritSect);
return TRUE;
} return ret;
/* 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;
} }
/***************************************************************** /*****************************************************************
...@@ -1231,38 +1170,90 @@ BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz) ...@@ -1231,38 +1170,90 @@ BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz)
*/ */
BOOL WINAPI DdeKeepStringHandle(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 */ /* If both are not found, return both "zero strings". */
return FALSE; ret = 0;
} }
else if (ret1 == 0)
if (!WDML_WaitForMutex(handle_mutex))
{ {
return FALSE; /* If hsz1 is a not found, return hsz1 is "zero string". */
ret = -1;
} }
else if (ret2 == 0)
/* First check instance
*/
thisInstance = WDML_FindInstance(idInst);
if ((thisInstance == NULL) || (thisInstance->nodeList == NULL))
{ {
if (WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE)) return FALSE; /* If hsz2 is a not found, return hsz2 is "zero string". */
/* Nothing has been initialised - exit now ! can return FALSE since effect is the same */ ret = 1;
return FALSE;
return FALSE;
} }
WDML_ReserveAtom(thisInstance, hsz); else
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); {
return TRUE; /* 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.@) * DdeCreateDataHandle (USER32.@)
*/ */
...@@ -1330,57 +1321,20 @@ HDDEDATA WINAPI DdeAddData(HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff) ...@@ -1330,57 +1321,20 @@ HDDEDATA WINAPI DdeAddData(HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff)
return hData; 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 * 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 * RETURNS
* Size of memory object associated with handle * Size of memory object associated with handle
*/ */
DWORD WINAPI DdeGetData( DWORD WINAPI DdeGetData(HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff)
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 dwSize, dwRet; DWORD dwSize, dwRet;
LPBYTE pByte; LPBYTE pByte;
...@@ -1475,247 +1429,64 @@ BOOL WINAPI DdeFreeDataHandle(HDDEDATA hData) ...@@ -1475,247 +1429,64 @@ BOOL WINAPI DdeFreeDataHandle(HDDEDATA hData)
* 0 16 bit fields for options (release, ackreq, response...) * 0 16 bit fields for options (release, ackreq, response...)
* 2 16 clipboard format * 2 16 clipboard format
* 4 ? data to be used * 4 ? data to be used
*/ */
HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem) HDDEDATA WDML_Global2DataHandle(HGLOBAL hMem, WINE_DDEHEAD* p)
{ {
DDEDATA* pDd; DDEDATA* pDd;
HDDEDATA ret = 0;
if (hMem)
{ if (hMem)
pDd = GlobalLock(hMem); {
if (pDd) pDd = GlobalLock(hMem);
{ if (pDd)
return DdeCreateDataHandle(0, pDd->Value, {
GlobalSize(hMem) - (sizeof(DDEDATA) - 1), if (p) memcpy(p, pDd, sizeof(WINE_DDEHEAD));
0, 0, pDd->cfFormat, 0); ret = DdeCreateDataHandle(0, pDd->Value,
} GlobalSize(hMem) - sizeof(WINE_DDEHEAD),
} 0, 0, pDd->cfFormat, 0);
return 0; GlobalUnlock(hMem);
} }
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;
}
} }
return ret; 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; DDE_DATAHANDLE_HEAD* pDdh;
CONVINFO ci; DWORD dwSize;
WDML_CONV* pConv; HGLOBAL hMem = 0;
FIXME("semi-stub.\n"); dwSize = GlobalSize(hDdeData) - sizeof(DDE_DATAHANDLE_HEAD);
pDdh = (DDE_DATAHANDLE_HEAD*)GlobalLock(hDdeData);
WDML_WaitForMutex(handle_mutex); if (dwSize && pDdh)
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
{ {
WDML_XACT* pXAct; hMem = GlobalAlloc(sizeof(WINE_DDEHEAD) + dwSize, GMEM_MOVEABLE | GMEM_DDESHARE);
if (hMem)
pXAct = WDML_FindTransaction(pConv, id); {
if (pXAct) WINE_DDEHEAD* wdh;
{
ci.hUser = pXAct->hUser; wdh = GlobalLock(hMem);
ci.hszItem = 0; /* FIXME */ if (wdh)
ci.wFmt = 0; /* FIXME */ {
ci.wType = 0; /* FIXME */ wdh->fResponse = fResponse;
} wdh->fRelease = fRelease;
else wdh->fDeferUpd = fDeferUpd;
{ wdh->fAckReq = fAckReq;
ret = 0; wdh->cfFormat = pDdh->cfFormat;
pConv->thisInstance->lastError = DMLERR_UNFOUND_QUEUE_ID; memcpy(wdh + 1, pDdh + 1, dwSize);
} GlobalUnlock(hMem);
}
}
GlobalUnlock(hDdeData);
} }
WDML_ReleaseMutex(handle_mutex, "hande_mutex", FALSE); return hMem;
memcpy(lpConvInfo, &ci, min(lpConvInfo->cb, sizeof(ci)));
return ret;
} }
/* ================================================================ /* ================================================================
...@@ -1729,19 +1500,28 @@ UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, LPCONVINFO lpConvInfo) ...@@ -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)); pServer = (WDML_SERVER*)HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_SERVER));
if (pServer == NULL) return NULL; if (pServer == NULL) return NULL;
pServer->hszService = hszService; WDML_IncHSZ(pInstance, pServer->hszService = hszService);
pServer->hszTopic = 0;
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->filterOn = TRUE;
pServer->next = thisInstance->servers; pServer->next = pInstance->servers;
thisInstance->servers = pServer; pInstance->servers = pServer;
return pServer; return pServer;
} }
...@@ -1750,34 +1530,54 @@ WDML_SERVER* WDML_AddServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hsz ...@@ -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* pPrev = NULL;
WDML_SERVER* pCurrent = NULL; WDML_SERVER* pServer = NULL;
WDML_CONV* pConv;
pCurrent = thisInstance->servers; 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 else
{ {
pPrev->next = pCurrent->next; pPrev->next = pServer->next;
} }
DestroyWindow(pCurrent->hwndServer); DestroyWindow(pServer->hwndServer);
WDML_DecHSZ(pInstance, pServer->hszServiceSpec);
HeapFree(GetProcessHeap(), 0, pCurrent); WDML_DecHSZ(pInstance, pServer->hszService);
GlobalDeleteAtom(pServer->atomService);
GlobalDeleteAtom(pServer->atomServiceSpec);
HeapFree(GetProcessHeap(), 0, pServer);
break; break;
} }
pPrev = pCurrent; pPrev = pServer;
pCurrent = pCurrent->next; pServer = pServer->next;
} }
} }
...@@ -1787,13 +1587,12 @@ void WDML_RemoveServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic ...@@ -1787,13 +1587,12 @@ void WDML_RemoveServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hszTopic
* generic routine to return a pointer to the relevant ServiceNode * generic routine to return a pointer to the relevant ServiceNode
* for a given service name, or NULL if the entry does not exist * 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; 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) if (hszService == pServer->hszService)
{ {
...@@ -1815,7 +1614,7 @@ WDML_SERVER* WDML_FindServer(WDML_INSTANCE* thisInstance, HSZ hszService, HSZ hs ...@@ -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) HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer)
{ {
WDML_CONV* pConv; WDML_CONV* pConv;
...@@ -1823,17 +1622,25 @@ WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, ...@@ -1823,17 +1622,25 @@ WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side,
/* no converstation yet, add it */ /* no converstation yet, add it */
pConv = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_CONV)); pConv = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_CONV));
if (!pConv) return NULL; if (!pConv) return NULL;
pConv->thisInstance = thisInstance; pConv->instance = pInstance;
pConv->hszService = hszService; WDML_IncHSZ(pInstance, pConv->hszService = hszService);
pConv->hszTopic = hszTopic; WDML_IncHSZ(pInstance, pConv->hszTopic = hszTopic);
pConv->hwndServer = hwndServer; pConv->hwndServer = hwndServer;
pConv->hwndClient = hwndClient; pConv->hwndClient = hwndClient;
pConv->transactions = NULL; pConv->transactions = NULL;
pConv->hUser = 0; 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]; pConv->next = pInstance->convs[side];
thisInstance->convs[side] = pConv; pInstance->convs[side] = pConv;
return pConv; return pConv;
} }
...@@ -1843,12 +1650,12 @@ WDML_CONV* WDML_AddConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, ...@@ -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) HSZ hszService, HSZ hszTopic)
{ {
WDML_CONV* pCurrent = NULL; 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 && if (DdeCmpStringHandles(pCurrent->hszService, hszService) == 0 &&
DdeCmpStringHandles(pCurrent->hszTopic, hszTopic) == 0) DdeCmpStringHandles(pCurrent->hszTopic, hszTopic) == 0)
...@@ -1865,21 +1672,48 @@ WDML_CONV* WDML_FindConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, ...@@ -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* pPrev = NULL;
WDML_CONV* pRef = WDML_GetConv(hConv); WDML_CONV* pCurrent;
WDML_CONV* pCurrent = NULL; WDML_XACT* pXAct;
WDML_XACT* pXActNext;
HWND hWnd;
if (!pRef) if (!pRef)
return; 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 == pRef)
{ {
if (pCurrent == thisInstance->convs[side]) if (pCurrent == pRef->instance->convs[side])
{ {
thisInstance->convs[side] = pCurrent->next; pRef->instance->convs[side] = pCurrent->next;
} }
else else
{ {
...@@ -1892,15 +1726,239 @@ void WDML_RemoveConv(WDML_INSTANCE* thisInstance, WDML_SIDE side, HCONV hConv) ...@@ -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_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 */ /* 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) ...@@ -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) UINT wType, HSZ hszItem, UINT wFmt)
{ {
WDML_LINK* pLink; WDML_LINK* pLink;
TRACE("AddDdeLink was called...\n");
pLink = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_LINK)); pLink = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_LINK));
if (pLink == NULL) if (pLink == NULL)
{ {
...@@ -1930,11 +1986,11 @@ void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side, ...@@ -1930,11 +1986,11 @@ void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
pLink->hConv = hConv; pLink->hConv = hConv;
pLink->transactionType = wType; pLink->transactionType = wType;
pLink->hszItem = hszItem; WDML_IncHSZ(pInstance, pLink->hszItem = hszItem);
pLink->uFmt = wFmt; pLink->uFmt = wFmt;
pLink->hDdeData = 0; pLink->hDdeData = 0;
pLink->next = thisInstance->links[side]; pLink->next = pInstance->links[side];
thisInstance->links[side] = pLink; pInstance->links[side] = pLink;
} }
/****************************************************************** /******************************************************************
...@@ -1942,13 +1998,13 @@ void WDML_AddLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side, ...@@ -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) HSZ hszItem, UINT uFmt)
{ {
WDML_LINK* pPrev = NULL; WDML_LINK* pPrev = NULL;
WDML_LINK* pCurrent = NULL; WDML_LINK* pCurrent = NULL;
pCurrent = thisInstance->links[side]; pCurrent = pInstance->links[side];
while (pCurrent != NULL) while (pCurrent != NULL)
{ {
...@@ -1956,9 +2012,9 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side, ...@@ -1956,9 +2012,9 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 && DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
pCurrent->uFmt == uFmt) pCurrent->uFmt == uFmt)
{ {
if (pCurrent == thisInstance->links[side]) if (pCurrent == pInstance->links[side])
{ {
thisInstance->links[side] = pCurrent->next; pInstance->links[side] = pCurrent->next;
} }
else else
{ {
...@@ -1969,7 +2025,8 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side, ...@@ -1969,7 +2025,8 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side,
{ {
DdeFreeDataHandle(pCurrent->hDdeData); DdeFreeDataHandle(pCurrent->hDdeData);
} }
WDML_DecHSZ(pInstance, pCurrent->hszItem);
HeapFree(GetProcessHeap(), 0, pCurrent); HeapFree(GetProcessHeap(), 0, pCurrent);
break; break;
} }
...@@ -1988,21 +2045,21 @@ void WDML_RemoveLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE side, ...@@ -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* pPrev = NULL;
WDML_LINK* pCurrent = NULL; WDML_LINK* pCurrent = NULL;
WDML_LINK* pNext = NULL; WDML_LINK* pNext = NULL;
pCurrent = thisInstance->links[side]; pCurrent = pInstance->links[side];
while (pCurrent != NULL) 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; pNext = pCurrent->next;
} }
else else
...@@ -2015,6 +2072,7 @@ void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE sid ...@@ -2015,6 +2072,7 @@ void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE sid
{ {
DdeFreeDataHandle(pCurrent->hDdeData); DdeFreeDataHandle(pCurrent->hDdeData);
} }
WDML_DecHSZ(pInstance, pCurrent->hszItem);
HeapFree(GetProcessHeap(), 0, pCurrent); HeapFree(GetProcessHeap(), 0, pCurrent);
pCurrent = NULL; pCurrent = NULL;
...@@ -2037,15 +2095,14 @@ void WDML_RemoveAllLinks(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE sid ...@@ -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) HSZ hszItem, UINT uFmt)
{ {
WDML_LINK* pCurrent = NULL; 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 /* we don't need to check for transaction type as it can be altered */
it can be altered */
if (pCurrent->hConv == hConv && if (pCurrent->hConv == hConv &&
DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 && DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
...@@ -2070,7 +2127,8 @@ WDML_LINK* WDML_FindLink(WDML_INSTANCE* thisInstance, HCONV hConv, WDML_SIDE si ...@@ -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 * 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; WDML_XACT* pXAct;
static WORD tid = 1; /* FIXME: wrap around */ static WORD tid = 1; /* FIXME: wrap around */
...@@ -2078,7 +2136,7 @@ WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg) ...@@ -2078,7 +2136,7 @@ WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg)
pXAct = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_XACT)); pXAct = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_XACT));
if (!pXAct) if (!pXAct)
{ {
thisInstance->lastError = DMLERR_MEMORY_ERROR; pInstance->lastError = DMLERR_MEMORY_ERROR;
return NULL; return NULL;
} }
...@@ -2087,7 +2145,13 @@ WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg) ...@@ -2087,7 +2145,13 @@ WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* thisInstance, UINT ddeMsg)
pXAct->hDdeData = 0; pXAct->hDdeData = 0;
pXAct->hUser = 0; pXAct->hUser = 0;
pXAct->next = NULL; 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; return pXAct;
} }
...@@ -2130,8 +2194,13 @@ BOOL WDML_UnQueueTransaction(WDML_CONV* pConv, WDML_XACT* 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); HeapFree(GetProcessHeap(), 0, pXAct);
} }
...@@ -2153,6 +2222,12 @@ WDML_XACT* WDML_FindTransaction(WDML_CONV* pConv, DWORD tid) ...@@ -2153,6 +2222,12 @@ WDML_XACT* WDML_FindTransaction(WDML_CONV* pConv, DWORD tid)
return pXAct; return pXAct;
} }
/* ================================================================
*
* Information broadcast across DDEML implementations
*
* ================================================================ */
struct tagWDML_BroadcastPmt struct tagWDML_BroadcastPmt
{ {
LPCSTR clsName; LPCSTR clsName;
......
...@@ -23,8 +23,9 @@ ...@@ -23,8 +23,9 @@
DEFAULT_DEBUG_CHANNEL(ddeml); DEFAULT_DEBUG_CHANNEL(ddeml);
static const char szServerNameClassA[] = "DdeServerNameAnsi"; static const char szServerNameClassA[] = "DdeServerNameAnsi";
static const char szServerConvClassA[] = "DdeServerConvAnsi"; 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_ServerNameProc(HWND, UINT, WPARAM, LPARAM);
static LRESULT CALLBACK WDML_ServerConvProc(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); ...@@ -32,60 +33,66 @@ static LRESULT CALLBACK WDML_ServerConvProc(HWND, UINT, WPARAM, LPARAM);
/****************************************************************************** /******************************************************************************
* DdePostAdvise [USER32.@] Send transaction to DDE callback function. * 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 * RETURNS
* Success: TRUE * Success: TRUE
* Failure: FALSE * Failure: FALSE
*/ */
BOOL WINAPI DdePostAdvise( BOOL WINAPI DdePostAdvise(DWORD idInst, HSZ hszTopic, HSZ hszItem)
DWORD idInst, /* [in] Instance identifier */
HSZ hszTopic, /* [in] Handle to topic name string */
HSZ hszItem) /* [in] Handle to item name string */
{ {
WDML_INSTANCE* thisInstance = NULL; WDML_INSTANCE* pInstance = NULL;
WDML_LINK* pLink = NULL; WDML_LINK* pLink = NULL;
HDDEDATA hDdeData = 0, hItemData = 0; HDDEDATA hDdeData = 0, hItemData = 0;
WDML_CONV* pConv = NULL; WDML_CONV* pConv = NULL;
CHAR pszTopic[MAX_BUFFER_LEN]; ATOM atom = 0;
CHAR pszItem[MAX_BUFFER_LEN]; 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); atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) goto theError;
if (thisInstance == NULL || thisInstance->links == NULL)
/* 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); for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
GlobalGetAtomNameA(hszItem, (LPSTR)pszItem, MAX_BUFFER_LEN);
for (pLink = thisInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next)
{ {
if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0) if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0)
{ {
hDdeData = 0; hDdeData = WDML_InvokeCallback(pInstance, XTYP_ADVREQ, pLink->uFmt, pLink->hConv,
if (thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId()*/) hszTopic, hszItem, 0, count--, 0);
{
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");
if (hDdeData == CBR_BLOCK)
{
/* MS doc is not consistent here */
FIXME("CBR_BLOCK returned for ADVREQ\n");
continue;
} }
if (hDdeData) if (hDdeData)
{ {
if (pLink->transactionType & XTYPF_NODATA) if (pLink->transactionType & XTYPF_NODATA)
...@@ -100,21 +107,33 @@ BOOL WINAPI DdePostAdvise( ...@@ -100,21 +107,33 @@ BOOL WINAPI DdePostAdvise(
hItemData = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE); 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 || if (!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer,
!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer, PackDDElParam(WM_DDE_DATA, (UINT)hItemData, atom)))
PackDDElParam(WM_DDE_DATA, (UINT)hItemData, (DWORD)hszItem)))
{ {
ERR("post message failed\n"); ERR("post message failed\n");
/* FIXME: wrong if app owned... */
DdeFreeDataHandle(hDdeData); DdeFreeDataHandle(hDdeData);
return FALSE; GlobalFree(hItemData);
goto theError;
} }
} }
} }
} }
LeaveCriticalSection(&WDML_CritSect);
return TRUE; return TRUE;
theError:
LeaveCriticalSection(&WDML_CritSect);
if (atom) GlobalDeleteAtom(atom);
return FALSE;
} }
...@@ -134,113 +153,64 @@ BOOL WINAPI DdePostAdvise( ...@@ -134,113 +153,64 @@ BOOL WINAPI DdePostAdvise(
HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd) HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
{ {
WDML_SERVER* pServer; WDML_SERVER* pServer;
WDML_SERVER* pServerTmp; WDML_INSTANCE* pInstance;
WDML_INSTANCE* thisInstance;
HDDEDATA hDdeData; HDDEDATA hDdeData;
HSZ hsz2nd = 0;
HWND hwndServer; HWND hwndServer;
WNDCLASSEXA wndclass; WNDCLASSEXA wndclass;
hDdeData = (HDDEDATA)NULL; hDdeData = (HDDEDATA)NULL;
TRACE("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd); TRACE("(%ld,0x%x,0x%x,%d)\n", idInst, hsz1, hsz2, afCmd);
if (WDML_MaxInstanceID == 0)
{
/* Nothing has been initialised - exit now !
* needs something for DdeGetLastError */
return 0;
}
if (!WDML_WaitForMutex(handle_mutex)) EnterCriticalSection(&WDML_CritSect);
{
/* FIXME: setError DMLERR_SYS_ERROR; */
return 0;
}
/* First check instance /* First check instance
*/ */
thisInstance = WDML_FindInstance(idInst); pInstance = WDML_GetInstance(idInst);
if (thisInstance == NULL) if (pInstance == NULL)
{ {
TRACE("Instance not found as initialised\n"); 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 */ /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
return FALSE; goto theError;
} }
if (hsz2 != 0L) if (hsz2 != 0L)
{ {
/* Illegal, reserved parameter /* Illegal, reserved parameter
*/ */
thisInstance->lastError = DMLERR_INVALIDPARAMETER; pInstance->lastError = DMLERR_INVALIDPARAMETER;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); WARN("Reserved parameter no-zero !!\n");
FIXME("Reserved parameter no-zero !!\n"); goto theError;
return FALSE;
} }
if (hsz1 == 0L) if (hsz1 == 0 && afCmd != DNS_UNREGISTER)
{ {
/* /* don't know if we should check this but it makes sense
* General unregister situation * why supply REGISTER or filter flags if de-registering all
*/
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
*/ */
if (thisInstance->servers == NULL) TRACE("General unregister unexpected flags\n");
{ pInstance->lastError = DMLERR_INVALIDPARAMETER;
/* None to unregister !! goto theError;
*/
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("Specific name action detected\n");
if (afCmd & DNS_REGISTER) switch (afCmd)
{ {
/* Register new service name case DNS_REGISTER:
*/ pServer = WDML_FindServer(pInstance, hsz1, 0);
pServer = WDML_FindServer(thisInstance, hsz1, 0);
if (pServer) 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.cbSize = sizeof(wndclass);
wndclass.style = 0; wndclass.style = 0;
...@@ -257,63 +227,59 @@ HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd) ...@@ -257,63 +227,59 @@ HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd)
RegisterClassExA(&wndclass); RegisterClassExA(&wndclass);
LeaveCriticalSection(&WDML_CritSect);
hwndServer = CreateWindowA(szServerNameClassA, NULL, hwndServer = CreateWindowA(szServerNameClassA, NULL,
WS_POPUP, 0, 0, 0, 0, WS_POPUP, 0, 0, 0, 0,
0, 0, 0, 0); 0, 0, 0, 0);
EnterCriticalSection(&WDML_CritSect);
SetWindowLongA(hwndServer, 0, (DWORD)thisInstance);
SetWindowLongA(hwndServer, GWL_WDML_INSTANCE, (DWORD)pInstance);
SetWindowLongA(hwndServer, GWL_WDML_SERVER, (DWORD)pServer);
TRACE("Created nameServer=%04x for instance=%08lx\n", hwndServer, idInst); TRACE("Created nameServer=%04x for instance=%08lx\n", hwndServer, idInst);
pServer->hwndServer = hwndServer; pServer->hwndServer = hwndServer;
} break;
if (afCmd & DNS_UNREGISTER)
{ case DNS_UNREGISTER:
TRACE("Broadcasting WM_DDE_TERMINATE message\n"); if (hsz1 == 0L)
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)
{ {
/* trying to filter where no service names !! /* General unregister situation
* terminate all server side pending conversations
*/ */
thisInstance->lastError = DMLERR_DLL_USAGE; while (pInstance->servers)
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); WDML_RemoveServer(pInstance, pInstance->servers->hszService, 0);
return FALSE; pInstance->servers = NULL;
} TRACE("General de-register - finished\n");
else }
else
{ {
pServer->filterOn = TRUE; WDML_RemoveServer(pInstance, hsz1, 0L);
} }
} break;
if (afCmd & DNS_FILTEROFF) case DNS_FILTERON:
{ case DNS_FILTEROFF:
/* Set filter flags on to hold notifications of connection /* Set filter flags on to hold notifications of connection
*/ */
pServer = WDML_FindServer(thisInstance, hsz1, 0); pServer = WDML_FindServer(pInstance, hsz1, 0);
if (!pServer) if (!pServer)
{ {
/* trying to filter where no service names !! /* trying to filter where no service names !!
*/ */
thisInstance->lastError = DMLERR_DLL_USAGE; pInstance->lastError = DMLERR_DLL_USAGE;
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); goto theError;
return FALSE; }
}
else else
{ {
pServer->filterOn = FALSE; pServer->filterOn = (afCmd == DNS_FILTERON);
} }
break;
} }
WDML_ReleaseMutex(handle_mutex, "handle_mutex", FALSE); LeaveCriticalSection(&WDML_CritSect);
return (HDDEDATA)TRUE; return (HDDEDATA)TRUE;
theError:
LeaveCriticalSection(&WDML_CritSect);
return FALSE;
} }
/****************************************************************** /******************************************************************
...@@ -321,56 +287,85 @@ HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd) ...@@ -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, static WDML_CONV* WDML_CreateServerConv(WDML_INSTANCE* pInstance, HWND hwndClient,
HSZ hszApp, HSZ hszTopic) HWND hwndServerName, HSZ hszApp, HSZ hszTopic)
{ {
WNDCLASSEXA wndclass;
HWND hwndServerConv; HWND hwndServerConv;
WDML_CONV* pConv; WDML_CONV* pConv;
wndclass.cbSize = sizeof(wndclass); if (pInstance->unicode)
wndclass.style = 0; {
wndclass.lpfnWndProc = WDML_ServerConvProc; WNDCLASSEXW wndclass;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.cbSize = sizeof(wndclass);
wndclass.hInstance = 0; wndclass.style = 0;
wndclass.hIcon = 0; wndclass.lpfnWndProc = WDML_ServerConvProc;
wndclass.hCursor = 0; wndclass.cbClsExtra = 0;
wndclass.hbrBackground = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD);
wndclass.lpszMenuName = NULL; wndclass.hInstance = 0;
wndclass.lpszClassName = szServerConvClassA; wndclass.hIcon = 0;
wndclass.hIconSm = 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, hwndServerConv = CreateWindowA(WDML_szServerConvClassA, 0,
WS_CHILD, 0, 0, 0, 0, WS_CHILD, 0, 0, 0, 0,
hwndServerName, 0, 0, 0); hwndServerName, 0, 0, 0);
}
TRACE("Created convServer=%04x (nameServer=%04x) for instance=%08lx\n", TRACE("Created convServer=%04x (nameServer=%04x) for instance=%08lx\n",
hwndServerConv, hwndServerName, thisInstance->instanceID); hwndServerConv, hwndServerName, pInstance->instanceID);
pConv = WDML_AddConv(thisInstance, WDML_SERVER_SIDE, hszApp, hszTopic, hwndClient, hwndServerConv);
SetWindowLongA(hwndServerConv, 0, (DWORD)thisInstance); pConv = WDML_AddConv(pInstance, WDML_SERVER_SIDE, hszApp, hszTopic,
SetWindowLongA(hwndServerConv, 4, (DWORD)pConv); hwndClient, hwndServerConv);
if (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()*/)
{ {
/* confirm connection... SetWindowLongA(hwndServerConv, GWL_WDML_INSTANCE, (DWORD)pInstance);
* FIXME: a better way would be to check for any incoming message if the conversation SetWindowLongA(hwndServerConv, GWL_WDML_CONVERSATION, (DWORD)pConv);
* exists (and/or) has been confirmed...
* Anyway, always pretend we use a connection from a different instance... /* 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 else
{
return TRUE; DestroyWindow(hwndServerConv);
}
return pConv;
} }
/****************************************************************** /******************************************************************
...@@ -383,8 +378,8 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w ...@@ -383,8 +378,8 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w
HWND hwndClient; HWND hwndClient;
HSZ hszApp, hszTop; HSZ hszApp, hszTop;
HDDEDATA hDdeData = 0; HDDEDATA hDdeData = 0;
WDML_INSTANCE* thisInstance; WDML_INSTANCE* pInstance;
UINT uiLow, uiHi; UINT uiLo, uiHi;
switch (iMsg) switch (iMsg)
{ {
...@@ -394,68 +389,97 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w ...@@ -394,68 +389,97 @@ static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM w
LOWORD(lParam) -- application atom LOWORD(lParam) -- application atom
HIWORD(lParam) -- topic 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; 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 */ /* don't free DDEParams, since this is a broadcast */
UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLow, &uiHi); UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLo, &uiHi);
hszApp = (HSZ)uiLow;
hszTop = (HSZ)uiHi;
thisInstance = (WDML_INSTANCE*)GetWindowLongA(hwndServer, 0); hszApp = WDML_MakeHszFromAtom(pInstance, uiLo);
TRACE("idInst=%ld, ProcessID=0x%lx\n", thisInstance->instanceID, GetCurrentProcessId()); hszTop = WDML_MakeHszFromAtom(pInstance, uiHi);
if (hszApp && hszTop) if (!(pInstance->CBFflags & CBF_FAIL_CONNECTIONS))
{ {
/* pass on to the callback */ BOOL self = FALSE;
if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/) 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", /* check filters for name service */
(DWORD)thisInstance->callback); if (!pServer->filterOn || DdeCmpStringHandles(pServer->hszService, hszApp) == 0)
hDdeData = (thisInstance->callback)(XTYP_CONNECT,
0, 0,
hszTop,
hszApp,
0, 0, 0);
if ((UINT)hDdeData)
{ {
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 if (pInstance->servers)
else
{
/* pass on to the callback */
if (thisInstance && thisInstance->callback != NULL /*&& thisInstance->Process_id == GetCurrentProcessId()*/)
{ {
TRACE("calling the Callback, type=XTYP_WILDCONNECT, CB=0x%lx\n", /* pass on to the callback */
(DWORD)thisInstance->callback); hDdeData = WDML_InvokeCallback(pInstance, XTYP_WILDCONNECT,
hDdeData = (thisInstance->callback)(XTYP_WILDCONNECT, 0, 0, hszTop, hszApp, 0, (DWORD)pcc, self);
0, 0,
hszTop, if (hDdeData == CBR_BLOCK)
hszApp, {
0, 0, 0); /* MS doc is not consistent here */
if ((UINT)hDdeData) FIXME("CBR_BLOCK returned for WILDCONNECT\n");
}
else if ((UINT)hDdeData != 0)
{ {
HSZPAIR* hszp; HSZPAIR* hszp;
hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL); hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL);
if (hszp) if (hszp)
{ {
int i; int i;
for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++) for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++)
{ {
WDML_CreateServerConv(thisInstance, hwndClient, hwndServer, pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer,
hszp[i].hszSvc, hszp[i].hszTopic); hszp[i].hszSvc, hszp[i].hszTopic);
} if (pConv && pcc) pConv->wStatus |= ST_ISLOCAL;
}
DdeUnaccessData(hDdeData); DdeUnaccessData(hDdeData);
} }
} }
} }
} }
/* /*
billx: make a conv and add it to the server list - billx: make a conv and add it to the server list -
this can be delayed when link is created for the conv. NO NEED !!! 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 ...@@ -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, static WDML_XACT* WDML_ServerQueueRequest(WDML_CONV* pConv, LPARAM lParam)
HWND hwndServer, HWND hwndClient, LPARAM lParam)
{ {
UINT uiLow, uiHi; UINT uiLo, uiHi;
HSZ hszItem; WDML_XACT* pXAct;
HDDEDATA hDdeData;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam); UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLo, &uiHi);
UnpackDDElParam(WM_DDE_REQUEST, lParam, &uiLow, &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", hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_REQUEST, pXAct->wFmt, (HCONV)pConv,
thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_REQUEST); pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
hDdeData = (thisInstance->callback)(XTYP_REQUEST, uiLow, (HCONV)pConv,
pConv->hszTopic, hszItem, 0, 0, 0);
} }
if (hDdeData) switch (hDdeData)
{ {
HGLOBAL hMem = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE); case 0:
if (!PostMessageA(hwndClient, WM_DDE_DATA, (WPARAM)hwndServer, WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, FALSE, pXAct->hszItem,
ReuseDDElParam(lParam, WM_DDE_REQUEST, WM_DDE_DATA, (UINT)hMem, (UINT)hszItem))) pXAct->lParam, WM_DDE_REQUEST);
{ break;
DdeFreeDataHandle(hDdeData); case CBR_BLOCK:
GlobalFree(hMem); 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 WDML_DecHSZ(pConv->instance, pXAct->hszItem);
{ return ret;
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_ServerHandleAdvise * WDML_ServerQueueAdvise
* *
* *
*/ */
static LRESULT WDML_ServerHandleAdvise(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, static WDML_XACT* WDML_ServerQueueAdvise(WDML_CONV* pConv, LPARAM lParam)
HWND hwndServer, HWND hwndClient, LPARAM lParam)
{ {
UINT uiLo, uiHi, uType; UINT uiLo, uiHi;
HGLOBAL hDdeAdvise; WDML_XACT* pXAct;
HSZ hszItem;
WDML_LINK* pLink;
DDEADVISE* pDdeAdvise;
HDDEDATA hDdeData;
DDEACK ddeAck;
/* XTYP_ADVSTART transaction: /* XTYP_ADVSTART transaction:
establish link and save link info to InstanceInfoTable */ establish link and save link info to InstanceInfoTable */
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi); UnpackDDElParam(WM_DDE_ADVISE, lParam, &uiLo, &uiHi);
hDdeAdvise = (HGLOBAL)uiLo; pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE,
hszItem = (HSZ)uiHi; /* FIXME: it should be a global atom */ 0, WDML_MakeHszFromAtom(pConv->instance, uiHi));
if (pXAct)
if (!pConv)
{ {
ERR("Got an advise on a not known conversation, dropping request\n"); pXAct->hMem = (HGLOBAL)uiLo;
FreeDDElParam(WM_DDE_ADVISE, lParam); pXAct->atom = uiHi;
return 0;
} }
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 | uType = XTYP_ADVSTART |
(pDdeAdvise->fDeferUpd ? XTYPF_NODATA : 0) | (pDdeAdvise->fDeferUpd ? XTYPF_NODATA : 0) |
(pDdeAdvise->fAckReq ? XTYPF_ACKREQ : 0); (pDdeAdvise->fAckReq ? XTYPF_ACKREQ : 0);
hDdeData = 0; if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
{ {
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x, uFmt=%x\n", hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_ADVSTART, pDdeAdvise->cfFormat,
thisInstance->instanceID, (DWORD)thisInstance->callback, (HCONV)pConv, pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
uType, pDdeAdvise->cfFormat); }
hDdeData = (thisInstance->callback)(XTYP_ADVSTART, pDdeAdvise->cfFormat, (HCONV)pConv, else
pConv->hszTopic, hszItem, 0, 0, 0); {
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. */ /* billx: first to see if the link is already created. */
pLink = WDML_FindLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
hszItem, pDdeAdvise->cfFormat); pXAct->hszItem, pDdeAdvise->cfFormat);
if (pLink != NULL) if (pLink != NULL)
{ {
...@@ -612,130 +643,135 @@ static LRESULT WDML_ServerHandleAdvise(WDML_INSTANCE* thisInstance, WDML_CONV* p ...@@ -612,130 +643,135 @@ static LRESULT WDML_ServerHandleAdvise(WDML_INSTANCE* thisInstance, WDML_CONV* p
{ {
TRACE("Adding Link with hConv=0x%lx\n", (DWORD)pConv); TRACE("Adding Link with hConv=0x%lx\n", (DWORD)pConv);
WDML_AddLink(thisInstance, (HCONV)pConv, WDML_SERVER_SIDE, WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_SERVER_SIDE,
uType, hszItem, pDdeAdvise->cfFormat); uType, pXAct->hszItem, pDdeAdvise->cfFormat);
} }
} }
else else
{ {
TRACE("No data returned from the Callback\n"); TRACE("No data returned from the Callback\n");
fAck = FALSE;
ddeAck.fAck = FALSE;
} }
GlobalUnlock(hDdeAdvise); GlobalUnlock(pXAct->hMem);
if (ddeAck.fAck) if (fAck)
GlobalFree(hDdeAdvise); GlobalFree(pXAct->hMem);
TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative"); WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, fAck, pXAct->atom, pXAct->lParam, WM_DDE_ADVISE);
PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer,
ReuseDDElParam(lParam, WM_DDE_ADVISE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem)); 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, static WDML_XACT* WDML_ServerQueueUnadvise(WDML_CONV* pConv, LPARAM lParam)
HWND hwndServer, HWND hwndClient, LPARAM lParam)
{ {
UINT uiLo, uiHi; UINT uiLo, uiHi;
HSZ hszItem; WDML_XACT* pXAct;
WDML_LINK* pLink;
DDEACK ddeAck;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam);
/* billx: XTYP_ADVSTOP transaction */
UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi); UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
/* uiLow: wFmt */ pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE,
hszItem = (HSZ)uiHi; /* FIXME: it should be a global atom */ 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) if (pLink == NULL)
{ {
ERR("Couln'd find link for %08lx, dropping request\n", (DWORD)hszItem); ERR("Couln'd find link for %08lx, dropping request\n", (DWORD)pXAct->hszItem);
FreeDDElParam(WM_DDE_UNADVISE, lParam); FreeDDElParam(WM_DDE_UNADVISE, pXAct->lParam);
return 0; return WDML_QS_ERROR;
} }
/* callback shouldn't be invoked if CBF_FAIL_ADVISES is on. */ if (!(pConv->instance->CBFflags & CBF_FAIL_ADVISES))
if (thisInstance && thisInstance->callback != NULL &&
!(thisInstance->CBFflags & CBF_SKIP_DISCONNECTS) /* && thisInstance->Process_id == GetCurrentProcessId() */)
{ {
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n", WDML_InvokeCallback(pConv->instance, XTYP_ADVSTOP, pXAct->wFmt, (HCONV)pConv,
thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_ADVSTOP); pConv->hszTopic, pXAct->hszItem, 0, 0, 0);
(thisInstance->callback)(XTYP_ADVSTOP, uiLo, (HCONV)pConv, pConv->hszTopic,
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 */ /* send back ack */
ddeAck.bAppReturnCode = 0; WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, FALSE, TRUE, pXAct->atom,
ddeAck.reserved = 0; pXAct->lParam, WM_DDE_UNADVISE);
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));
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, static WDML_XACT* WDML_ServerQueueExecute(WDML_CONV* pConv, LPARAM lParam)
HWND hwndServer, HWND hwndClient, LPARAM lParam)
{ {
DDEACK ddeAck; WDML_XACT* pXAct;
HDDEDATA hDdeData;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam); pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
if (pXAct)
if (hwndClient != pConv->hwndClient) {
WARN("hmmm source window (%04x)\n", hwndClient); 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 (!(pConv->instance->CBFflags & CBF_FAIL_EXECUTES))
if (thisInstance && thisInstance->callback != NULL /* && thisInstance->Process_id == GetCurrentProcessId() */)
{ {
LPVOID ptr = GlobalLock((HGLOBAL)lParam); LPVOID ptr = GlobalLock(pXAct->hMem);
if (ptr) if (ptr)
{ {
hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize((HGLOBAL)lParam), hDdeData = DdeCreateDataHandle(0, ptr, GlobalSize(pXAct->hMem),
0, 0, CF_TEXT, 0); 0, 0, CF_TEXT, 0);
GlobalUnlock((HGLOBAL)lParam); GlobalUnlock(pXAct->hMem);
} }
TRACE("calling the Callback, idInst=%ld, CB=0x%lx, uType=0x%x\n", hDdeData = WDML_InvokeCallback(pConv->instance, XTYP_EXECUTE, 0, (HCONV)pConv,
thisInstance->instanceID, (DWORD)thisInstance->callback, XTYP_EXECUTE); pConv->hszTopic, 0, hDdeData, 0L, 0L);
hDdeData = (thisInstance->callback)(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) switch ((UINT)hDdeData)
{ {
case DDE_FACK: case DDE_FACK:
ddeAck.fAck = TRUE; fAck = TRUE;
break; break;
case DDE_FBUSY: case DDE_FBUSY:
ddeAck.fBusy = TRUE; fBusy = TRUE;
break; break;
default: default:
WARN("Bad result code\n"); WARN("Bad result code\n");
...@@ -743,63 +779,69 @@ static LRESULT WDML_ServerHandleExecute(WDML_INSTANCE* thisInstance, WDML_CONV* ...@@ -743,63 +779,69 @@ static LRESULT WDML_ServerHandleExecute(WDML_INSTANCE* thisInstance, WDML_CONV*
case DDE_FNOTPROCESSED: case DDE_FNOTPROCESSED:
break; break;
} }
PostMessageA(pConv->hwndClient, WM_DDE_ACK, (WPARAM)hwndServer, WDML_PostAck(pConv, WDML_SERVER_SIDE, 0, fBusy, fAck, pXAct->hMem, 0, 0);
PackDDElParam(WM_DDE_ACK, *((WORD*)&ddeAck), lParam));
return 0; return WDML_QS_HANDLED;
} }
/****************************************************************** /******************************************************************
* WDML_ServerHandlePoke * WDML_ServerQueuePoke
* *
* *
*/ */
static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, static WDML_XACT* WDML_ServerQueuePoke(WDML_CONV* pConv, LPARAM lParam)
HWND hwndServer, HWND hwndClient, LPARAM lParam)
{ {
UINT uiLo, uiHi; UINT uiLo, uiHi;
HSZ hszItem; WDML_XACT* pXAct;
DDEACK ddeAck;
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; DDEPOKE* pDdePoke;
HDDEDATA hDdeData; HDDEDATA hDdeData;
BOOL fBusy = FALSE, fAck = FALSE;
TRACE("(%04x %04x %08lx)!\n", hwndServer, hwndClient, lParam); pDdePoke = (DDEPOKE*)GlobalLock(pXAct->hMem);
UnpackDDElParam(WM_DDE_UNADVISE, lParam, &uiLo, &uiHi);
hszItem = (HSZ)uiHi;
pDdePoke = (DDEPOKE*)GlobalLock((HGLOBAL)uiLo);
if (!pDdePoke) if (!pDdePoke)
{ {
return 0; return WDML_QS_ERROR;
} }
ddeAck.bAppReturnCode = 0; if (!(pConv->instance->CBFflags & CBF_FAIL_POKES))
ddeAck.reserved = 0;
ddeAck.fBusy = FALSE;
ddeAck.fAck = FALSE;
if (thisInstance && thisInstance->callback != NULL)
{ {
hDdeData = DdeCreateDataHandle(thisInstance->instanceID, pDdePoke->Value, hDdeData = DdeCreateDataHandle(pConv->instance->instanceID, pDdePoke->Value,
GlobalSize((HGLOBAL)uiLo) - sizeof(DDEPOKE) + 1, GlobalSize(pXAct->hMem) - sizeof(DDEPOKE) + 1,
0, 0, pDdePoke->cfFormat, 0); 0, 0, pDdePoke->cfFormat, 0);
if (hDdeData) if (hDdeData)
{ {
HDDEDATA hDdeDataOut; HDDEDATA hDdeDataOut;
TRACE("calling callback XTYP_POKE, idInst=%ld\n", hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_POKE, pDdePoke->cfFormat,
thisInstance->instanceID); (HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
hDdeDataOut = (thisInstance->callback)(XTYP_POKE, hDdeData, 0, 0);
pDdePoke->cfFormat, (HCONV)pConv,
pConv->hszTopic, (HSZ)uiHi,
hDdeData, 0, 0);
switch ((UINT)hDdeDataOut) switch ((UINT)hDdeDataOut)
{ {
case DDE_FACK: case DDE_FACK:
ddeAck.fAck = TRUE; fAck = TRUE;
break; break;
case DDE_FBUSY: case DDE_FBUSY:
ddeAck.fBusy = TRUE; fBusy = TRUE;
break; break;
default: default:
FIXME("Unsupported returned value %08lx\n", (DWORD)hDdeDataOut); FIXME("Unsupported returned value %08lx\n", (DWORD)hDdeDataOut);
...@@ -810,15 +852,29 @@ static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pCo ...@@ -810,15 +852,29 @@ static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pCo
DdeFreeDataHandle(hDdeData); DdeFreeDataHandle(hDdeData);
} }
} }
GlobalUnlock((HGLOBAL)uiLo); GlobalUnlock(pXAct->hMem);
if (!ddeAck.fAck)
GlobalFree((HGLOBAL)uiHi);
PostMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServer, if (!fAck)
ReuseDDElParam(lParam, WM_DDE_POKE, WM_DDE_ACK, *((WORD*)&ddeAck), (UINT)hszItem)); 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 ...@@ -826,34 +882,69 @@ static LRESULT WDML_ServerHandlePoke(WDML_INSTANCE* thisInstance, WDML_CONV* pCo
* *
* *
*/ */
static LRESULT WDML_ServerHandleTerminate(WDML_INSTANCE* thisInstance, WDML_CONV* pConv, static WDML_QUEUE_STATE WDML_ServerHandleTerminate(WDML_CONV* pConv, WDML_XACT* pXAct)
HWND hwndServer, HWND hwndClient, LPARAM lParam)
{ {
UINT uiLo, uiHi; /* billx: two things to remove: the conv, and associated links.
HSZ hszApp, hszTop; * 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"); return WDML_QS_HANDLED;
/* 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.*/ * WDML_ServerHandle
*
/* don't free DDEParams, since this is a broadcast */ *
UnpackDDElParam(WM_DDE_TERMINATE, lParam, &uiLo, &uiHi); */
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; case WM_DDE_UNADVISE:
hszTop = (HSZ)uiHi; qs = WDML_ServerHandleUnadvise(pConv, pXAct);
break;
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_UNREGISTER, hszApp, hszTop); case WM_DDE_EXECUTE:
qs = WDML_ServerHandleExecute(pConv, pXAct);
/* PostMessageA(hwndClient, WM_DDE_TERMINATE, (WPARAM)hwndServer, (LPARAM)hConv); */ break;
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. */
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 ...@@ -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) static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam)
{ {
WDML_INSTANCE* thisInstance; WDML_INSTANCE* pInstance;
WDML_CONV* pConv; 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) if (iMsg < WM_DDE_FIRST || iMsg > WM_DDE_LAST)
{ {
return DefWindowProcA(hwndServer, iMsg, wParam, lParam); 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) switch (iMsg)
{ {
case WM_DDE_INITIATE: case WM_DDE_INITIATE:
FIXME("WM_DDE_INITIATE message received in the ServerConv Proc!\n"); FIXME("WM_DDE_INITIATE message received!\n");
break; break;
case WM_DDE_REQUEST: case WM_DDE_REQUEST:
WDML_ServerHandleRequest(thisInstance, pConv, hwndServer, (HWND)wParam, lParam); pXAct = WDML_ServerQueueRequest(pConv, lParam);
break; break;
case WM_DDE_ADVISE: case WM_DDE_ADVISE:
WDML_ServerHandleAdvise(thisInstance, pConv, hwndServer, (HWND)wParam, lParam); pXAct = WDML_ServerQueueAdvise(pConv, lParam);
break; break;
case WM_DDE_UNADVISE: case WM_DDE_UNADVISE:
WDML_ServerHandleUnadvise(thisInstance, pConv, hwndServer, (HWND)wParam, lParam); pXAct = WDML_ServerQueueUnadvise(pConv, lParam);
break; break;
case WM_DDE_EXECUTE: case WM_DDE_EXECUTE:
WDML_ServerHandleExecute(thisInstance, pConv, hwndServer, (HWND)wParam, lParam); pXAct = WDML_ServerQueueExecute(pConv, lParam);
break; break;
case WM_DDE_POKE: case WM_DDE_POKE:
WDML_ServerHandlePoke(thisInstance, pConv, hwndServer, (HWND)wParam, lParam); pXAct = WDML_ServerQueuePoke(pConv, lParam);
break; break;
case WM_DDE_TERMINATE: case WM_DDE_TERMINATE:
WDML_ServerHandleTerminate(thisInstance, pConv, hwndServer, (HWND)wParam, lParam); pXAct = WDML_ServerQueueTerminate(pConv, lParam);
break; break;
case WM_DDE_ACK: case WM_DDE_ACK:
...@@ -918,8 +1031,20 @@ static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM w ...@@ -918,8 +1031,20 @@ static LRESULT CALLBACK WDML_ServerConvProc(HWND hwndServer, UINT iMsg, WPARAM w
default: default:
FIXME("Unsupported message %d\n", iMsg); 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; return 0;
} }
...@@ -26,7 +26,7 @@ debug_channels (accel caret class clipboard combo cursor dc dde ddeml dialog dri ...@@ -26,7 +26,7 @@ debug_channels (accel caret class clipboard combo cursor dc dde ddeml dialog dri
@ stdcall BringWindowToTop(long) BringWindowToTop @ stdcall BringWindowToTop(long) BringWindowToTop
@ stdcall BroadcastSystemMessage(long ptr long long long) BroadcastSystemMessage @ stdcall BroadcastSystemMessage(long ptr long long long) BroadcastSystemMessage
@ stdcall CalcChildScroll(long long) CalcChildScroll @ stdcall CalcChildScroll(long long) CalcChildScroll
@ stub CallMsgFilter @ stdcall CallMsgFilter(ptr long) CallMsgFilterA
@ stdcall CallMsgFilterA(ptr long) CallMsgFilterA @ stdcall CallMsgFilterA(ptr long) CallMsgFilterA
@ stdcall CallMsgFilterW(ptr long) CallMsgFilterW @ stdcall CallMsgFilterW(ptr long) CallMsgFilterW
@ stdcall CallNextHookEx(long long long long) CallNextHookEx @ stdcall CallNextHookEx(long long long long) CallNextHookEx
...@@ -107,8 +107,8 @@ debug_channels (accel caret class clipboard combo cursor dc dde ddeml dialog dri ...@@ -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 DdeConnect(long long long ptr) DdeConnect
@ stdcall DdeConnectList(long long long long ptr) DdeConnectList @ stdcall DdeConnectList(long long long long ptr) DdeConnectList
@ stdcall DdeCreateDataHandle(long ptr long long long long long) DdeCreateDataHandle @ stdcall DdeCreateDataHandle(long ptr long long long long long) DdeCreateDataHandle
@ stdcall DdeCreateStringHandleA(long str long) DdeCreateStringHandleA @ stdcall DdeCreateStringHandleA(long ptr long) DdeCreateStringHandleA
@ stdcall DdeCreateStringHandleW(long wstr long) DdeCreateStringHandleW @ stdcall DdeCreateStringHandleW(long ptr long) DdeCreateStringHandleW
@ stdcall DdeDisconnect(long) DdeDisconnect @ stdcall DdeDisconnect(long) DdeDisconnect
@ stdcall DdeDisconnectList(long) DdeDisconnectList @ stdcall DdeDisconnectList(long) DdeDisconnectList
@ stdcall DdeEnableCallback(long long long) DdeEnableCallback @ stdcall DdeEnableCallback(long long long) DdeEnableCallback
......
...@@ -262,6 +262,9 @@ static void thread_detach(void) ...@@ -262,6 +262,9 @@ static void thread_detach(void)
{ {
HQUEUE16 hQueue = GetThreadQueue16( 0 ); HQUEUE16 hQueue = GetThreadQueue16( 0 );
extern void WDML_NotifyThreadDetach(void);
WDML_NotifyThreadDetach();
if (hQueue) if (hQueue)
{ {
TIMER_RemoveQueueTimers( hQueue ); TIMER_RemoveQueueTimers( hQueue );
......
...@@ -177,6 +177,8 @@ extern "C" { ...@@ -177,6 +177,8 @@ extern "C" {
#define TIMEOUT_ASYNC 0xFFFFFFFF #define TIMEOUT_ASYNC 0xFFFFFFFF
#define CADV_LATEACK 0xFFFF
/************************************************** /**************************************************
End of Message Types Section End of Message Types Section
...@@ -332,6 +334,7 @@ BOOL WINAPI DdeFreeStringHandle(DWORD,HSZ); ...@@ -332,6 +334,7 @@ BOOL WINAPI DdeFreeStringHandle(DWORD,HSZ);
BOOL WINAPI DdeFreeDataHandle(HDDEDATA); BOOL WINAPI DdeFreeDataHandle(HDDEDATA);
BOOL WINAPI DdeKeepStringHandle(DWORD,HSZ); BOOL WINAPI DdeKeepStringHandle(DWORD,HSZ);
HDDEDATA WINAPI DdeClientTransaction(LPBYTE,DWORD,HCONV,HSZ,UINT,UINT,DWORD,LPDWORD); 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 DdeImpersonateClient(HCONV);
BOOL WINAPI DdePostAdvise(DWORD,HSZ,HSZ); BOOL WINAPI DdePostAdvise(DWORD,HSZ,HSZ);
HDDEDATA WINAPI DdeAddData(HDDEDATA,LPBYTE,DWORD,DWORD); 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