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