[1/2] user32: Reorder some DDE functions to avoid the need for forward declarations.

Francois Gouget fgouget at free.fr
Tue Jun 12 03:24:45 CDT 2012


---
 dlls/user32/dde_misc.c | 2052 ++++++++++++++++++++++++------------------------
 1 file changed, 1029 insertions(+), 1023 deletions(-)

diff --git a/dlls/user32/dde_misc.c b/dlls/user32/dde_misc.c
index b40af66..d8a43ec 100644
--- a/dlls/user32/dde_misc.c
+++ b/dlls/user32/dde_misc.c
@@ -250,1024 +250,1030 @@ BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, CONST SECURITY_QUALITY_OF_SE
 
 /* ================================================================
  *
- * 			Instance management
+ * 			WDML Error management
  *
  * ================================================================ */
 
 /******************************************************************************
- *		IncrementInstanceId
+ * DdeGetLastError [USER32.@]  Gets most recent error code
  *
- *	generic routine to increment the max instance Id and allocate a new application instance
+ * PARAMS
+ *    idInst [I] Instance identifier
+ *
+ * RETURNS
+ *    Last error code
  */
-static void WDML_IncrementInstanceId(WDML_INSTANCE* pInstance)
+UINT WINAPI DdeGetLastError(DWORD idInst)
 {
-    DWORD	id = InterlockedIncrement(&WDML_MaxInstanceID);
+    DWORD		error_code;
+    WDML_INSTANCE*	pInstance;
 
-    pInstance->instanceID = id;
-    TRACE("New instance id %d allocated\n", id);
+    /*  First check instance
+     */
+    pInstance = WDML_GetInstance(idInst);
+    if  (pInstance == NULL)
+    {
+	error_code = DMLERR_INVALIDPARAMETER;
+    }
+    else
+    {
+	error_code = pInstance->lastError;
+	pInstance->lastError = 0;
+    }
+
+    return error_code;
 }
 
 /******************************************************************
- *		WDML_EventProc
+ *		WDML_SetAllLastError
  *
  *
  */
-static LRESULT CALLBACK WDML_EventProc(HWND hwndEvent, UINT uMsg, WPARAM wParam, LPARAM lParam)
+static void	WDML_SetAllLastError(DWORD lastError)
 {
+    DWORD		threadID;
     WDML_INSTANCE*	pInstance;
-    HSZ			hsz1, hsz2;
-
-    switch (uMsg)
+    threadID = GetCurrentThreadId();
+    pInstance = WDML_InstanceList;
+    while (pInstance)
     {
-    case WM_WDML_REGISTER:
-	pInstance = WDML_GetInstanceFromWnd(hwndEvent);
-        /* try calling the Callback */
-	if (pInstance && !(pInstance->CBFflags & CBF_SKIP_REGISTRATIONS))
-	{
-	    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:
-	pInstance = WDML_GetInstanceFromWnd(hwndEvent);
-	if (pInstance && !(pInstance->CBFflags & CBF_SKIP_UNREGISTRATIONS))
-	{
-	    hsz1 = WDML_MakeHszFromAtom(pInstance, wParam);
-	    hsz2 = WDML_MakeHszFromAtom(pInstance, lParam);
-	    WDML_InvokeCallback(pInstance, XTYP_UNREGISTER, 0, 0, hsz1, hsz2, 0, 0, 0);
-	    WDML_DecHSZ(pInstance, hsz1);
-	    WDML_DecHSZ(pInstance, hsz2);
-	}
-	break;
-
-    case WM_WDML_CONNECT_CONFIRM:
-	pInstance = WDML_GetInstanceFromWnd(hwndEvent);
-	if (pInstance && !(pInstance->CBFflags & CBF_SKIP_CONNECT_CONFIRMS))
-	{
-	    WDML_CONV*	pConv;
-	    /* confirm connection...
-	     * lookup for this conv handle
-	     */
-            HWND client = WIN_GetFullHandle( (HWND)wParam );
-            HWND server = WIN_GetFullHandle( (HWND)lParam );
-	    for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConv->next)
-	    {
-		if (pConv->hwndClient == client && pConv->hwndServer == server)
-		    break;
-	    }
-	    if (pConv)
-	    {
-		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 DefWindowProcW(hwndEvent, uMsg, wParam, lParam);
+	if (pInstance->threadID == threadID)
+	    pInstance->lastError = lastError;
+	pInstance = pInstance->next;
     }
-    return 0;
 }
 
+/* ================================================================
+ *
+ * 			String management
+ *
+ * ================================================================ */
+
+
 /******************************************************************
- *		WDML_Initialize
+ *		WDML_FindNode
  *
  *
  */
-UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback,
-		     DWORD afCmd, DWORD ulRes, BOOL bUnicode)
+static HSZNode*	WDML_FindNode(WDML_INSTANCE* pInstance, HSZ hsz)
 {
-    WDML_INSTANCE*		pInstance;
-    WDML_INSTANCE*		reference_inst;
-    UINT			ret;
-    WNDCLASSEXW			wndclass;
-
-    TRACE("(%p,%p,0x%x,%d,0x%x)\n",
-	  pidInst, pfnCallback, afCmd, ulRes, bUnicode);
+    HSZNode*	pNode;
 
-    if (ulRes)
-    {
-	ERR("Reserved value not zero?  What does this mean?\n");
-	/* trap this and no more until we know more */
-	return DMLERR_NO_ERROR;
-    }
+    if (pInstance == NULL) return NULL;
 
-    /* grab enough heap for one control struct - not really necessary for re-initialise
-     *	but allows us to use same validation routines */
-    pInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE));
-    if (pInstance == NULL)
+    for (pNode = pInstance->nodeList; pNode != NULL; pNode = pNode->next)
     {
-	/* catastrophe !! warn user & abort */
-	ERR("Instance create failed - out of memory\n");
-	return DMLERR_SYS_ERROR;
+	if (pNode->hsz == hsz) break;
     }
-    pInstance->next = NULL;
-    pInstance->monitor = (afCmd | APPCLASS_MONITOR);
+    if (!pNode) WARN("HSZ %p not found\n", hsz);
+    return pNode;
+}
 
-    /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
+/******************************************************************
+ *		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];
 
-    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->nodeList = NULL; /* node will be added later */
-    pInstance->monitorFlags = afCmd & MF_MASK;
-    pInstance->wStatus = 0;
-    pInstance->lastError = DMLERR_NO_ERROR;
-    pInstance->servers = NULL;
-    pInstance->convs[0] = NULL;
-    pInstance->convs[1] = NULL;
-    pInstance->links[0] = NULL;
-    pInstance->links[1] = NULL;
+    if (GetAtomNameW(HSZ2ATOM(hsz), nameBuffer, MAX_BUFFER_LEN))
+	return GlobalAddAtomW(nameBuffer);
+    WARN("HSZ %p not found\n", hsz);
+    return 0;
+}
 
-    /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
+/******************************************************************
+ *		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(const WDML_INSTANCE* pInstance, ATOM atom)
+{
+    WCHAR nameBuffer[MAX_BUFFER_LEN];
 
-    pInstance->CBFflags = afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
+    if (!atom) return NULL;
 
-    if (!pInstance->clientOnly)
+    if (GlobalGetAtomNameW(atom, nameBuffer, MAX_BUFFER_LEN))
     {
-	/* Check for other way of setting Client-only !! */
-	pInstance->clientOnly =
-	    (pInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS;
+	TRACE("%x => %s\n", atom, debugstr_w(nameBuffer));
+	return DdeCreateStringHandleW(pInstance->instanceID, nameBuffer, CP_WINUNICODE);
     }
+    WARN("ATOM 0x%x not found\n", atom);
+    return 0;
+}
 
-    TRACE("instance created - checking validity\n");
-
-    if (*pidInst == 0)
-    {
-	/*  Initialisation of new Instance Identifier */
-	TRACE("new instance, callback %p flags %X\n",pfnCallback,afCmd);
+/******************************************************************
+ *		WDML_IncHSZ
+ *
+ *
+ */
+BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
+{
+    HSZNode*	pNode;
 
-	EnterCriticalSection(&WDML_CritSect);
+    pNode = WDML_FindNode(pInstance, hsz);
+    if (!pNode) return FALSE;
 
-	if (WDML_InstanceList == NULL)
-	{
-	    /* can't be another instance in this case, assign to the base pointer */
-	    WDML_InstanceList = pInstance;
+    pNode->refCount++;
+    return TRUE;
+}
 
-	    /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
-	     *		present
-	     *	-------------------------------      NOTE NOTE NOTE    --------------------------
-	     *
-	     *	the manual is not clear if this condition
-	     *	applies to the first call to DdeInitialize from an application, or the
-	     *	first call for a given callback !!!
-	     */
+/******************************************************************************
+ *           WDML_DecHSZ    (INTERNAL)
+ *
+ * Decrease the ref count of an HSZ. If it reaches 0, the node is removed from the list
+ * of HSZ nodes
+ * Returns -1 is the HSZ isn't found, otherwise it's the current (after --) of the ref count
+ */
+BOOL WDML_DecHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
+{
+    HSZNode* 	pPrev = NULL;
+    HSZNode* 	pCurrent;
 
-	    pInstance->CBFflags = pInstance->CBFflags|APPCMD_FILTERINITS;
-	    TRACE("First application instance detected OK\n");
-	    /*	allocate new instance ID */
-	    WDML_IncrementInstanceId(pInstance);
-	}
-	else
+    for (pCurrent = pInstance->nodeList; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next)
+    {
+	/* If we found the node we were looking for and its ref count is one,
+	 * we can remove it
+	 */
+	if (pCurrent->hsz == hsz)
 	{
-	    /* really need to chain the new one in to the latest here, but after checking conditions
-	     *	such as trying to start a conversation from an application trying to monitor */
-	    reference_inst = WDML_InstanceList;
-	    TRACE("Subsequent application instance - starting checks\n");
-	    while (reference_inst->next != NULL)
+	    if (--pCurrent->refCount == 0)
 	    {
-		/*
-		 *	This set of tests will work if application uses same instance Id
-		 *	at application level once allocated - which is what manual implies
-		 *	should happen. If someone tries to be
-		 *	clever (lazy ?) it will fail to pick up that later calls are for
-		 *	the same application - should we trust them ?
-		 */
-		if (pInstance->instanceID == reference_inst->instanceID)
-		{
-		    /* Check 1 - must be same Client-only state */
-
-		    if (pInstance->clientOnly != reference_inst->clientOnly)
-		    {
-			ret = DMLERR_DLL_USAGE;
-			goto theError;
-		    }
-
-		    /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
-
-		    if (pInstance->monitor != reference_inst->monitor)
-		    {
-			ret = DMLERR_INVALIDPARAMETER;
-			goto theError;
-		    }
-
-		    /* Check 3 - must supply different callback address */
-
-		    if (pInstance->callback == reference_inst->callback)
-		    {
-			ret = DMLERR_DLL_USAGE;
-			goto theError;
-		    }
-		}
-		reference_inst = reference_inst->next;
-	    }
-	    /*  All cleared, add to chain */
-
-	    TRACE("Application Instance checks finished\n");
-	    WDML_IncrementInstanceId(pInstance);
-	    reference_inst->next = pInstance;
-	}
-	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(ULONG_PTR);
-	wndclass.hInstance     = 0;
-	wndclass.hIcon         = 0;
-	wndclass.hCursor       = 0;
-	wndclass.hbrBackground = 0;
-	wndclass.lpszMenuName  = NULL;
-	wndclass.lpszClassName = WDML_szEventClass;
-	wndclass.hIconSm       = 0;
-
-	RegisterClassExW(&wndclass);
-
-	pInstance->hwndEvent = CreateWindowW(WDML_szEventClass, NULL,
-						WS_POPUP, 0, 0, 0, 0,
-						0, 0, 0, 0);
-
-	SetWindowLongPtrW(pInstance->hwndEvent, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance);
-
-	TRACE("New application instance processing finished OK\n");
-    }
-    else
-    {
-	/* Reinitialisation situation   --- FIX  */
-	TRACE("reinitialisation of (%p,%p,0x%x,%d): stub\n", pidInst, pfnCallback, afCmd, ulRes);
-
-	EnterCriticalSection(&WDML_CritSect);
-
-	if (WDML_InstanceList == NULL)
-	{
-	    ret = DMLERR_INVALIDPARAMETER;
-	    goto theError;
-	}
-	/* 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 ? */
-	/*
-	 *	MS allows initialisation without specifying a callback, should we allow addition of the
-	 *	callback by a later call to initialise ? - if so this lot will have to change
-	 */
-	while (reference_inst->next != NULL)
-	{
-	    if (*pidInst == reference_inst->instanceID && pfnCallback == reference_inst->callback)
-	    {
-		/* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
-
-		if (reference_inst->clientOnly)
-		{
-		    if  ((reference_inst->CBFflags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
-		    {
-				/* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
-
-			if (!(afCmd & APPCMD_CLIENTONLY))
-			{
-			    ret = DMLERR_INVALIDPARAMETER;
-			    goto theError;
-			}
-		    }
-		}
-		/* Check 2 - cannot change monitor modes */
-
-		if (pInstance->monitor != reference_inst->monitor)
+		if (pCurrent == pInstance->nodeList)
 		{
-		    ret = DMLERR_INVALIDPARAMETER;
-		    goto theError;
+		    pInstance->nodeList = pCurrent->next;
 		}
-
-		/* Check 3 - trying to set Client-only via APPCMD when not set so previously */
-
-		if ((afCmd&APPCMD_CLIENTONLY) && !reference_inst->clientOnly)
+		else
 		{
-		    ret = DMLERR_INVALIDPARAMETER;
-		    goto theError;
+		    pPrev->next = pCurrent->next;
 		}
-		break;
+		HeapFree(GetProcessHeap(), 0, pCurrent);
+		DeleteAtom(HSZ2ATOM(hsz));
 	    }
-	    reference_inst = reference_inst->next;
-	}
-	if (reference_inst->next == NULL)
-	{
-	    ret = DMLERR_INVALIDPARAMETER;
-	    goto theError;
+	    return TRUE;
 	}
-	/* All checked - change relevant flags */
-
-	reference_inst->CBFflags = pInstance->CBFflags;
-	reference_inst->clientOnly = pInstance->clientOnly;
-	reference_inst->monitorFlags = pInstance->monitorFlags;
-
-	HeapFree(GetProcessHeap(), 0, pInstance); /* finished - release heap space used as work store */
-
-	LeaveCriticalSection(&WDML_CritSect);
     }
+    WARN("HSZ %p not found\n", hsz);
 
-    return DMLERR_NO_ERROR;
- theError:
-    HeapFree(GetProcessHeap(), 0, pInstance);
-    LeaveCriticalSection(&WDML_CritSect);
-    return ret;
+    return FALSE;
 }
 
 /******************************************************************************
- *            DdeInitializeA   (USER32.@)
+ *            WDML_FreeAllHSZ    (INTERNAL)
  *
- * See DdeInitializeW.
+ * Frees up all the strings still allocated in the list and
+ * remove all the nodes from the list of HSZ nodes.
  */
-UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback,
-			   DWORD afCmd, DWORD ulRes)
+void WDML_FreeAllHSZ(WDML_INSTANCE* pInstance)
 {
-    return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, FALSE);
+    /* Free any strings created in this instance.
+     */
+    while (pInstance->nodeList != NULL)
+    {
+	DdeFreeStringHandle(pInstance->instanceID, pInstance->nodeList->hsz);
+    }
 }
 
 /******************************************************************************
- * 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
+ *            InsertHSZNode    (INTERNAL)
  *
- * RETURNS
- *    Success: DMLERR_NO_ERROR
- *    Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
+ * Insert a node to the head of the list.
  */
-UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
-			   DWORD afCmd, DWORD ulRes)
+static void WDML_InsertHSZNode(WDML_INSTANCE* pInstance, HSZ hsz)
 {
-    return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE);
+    if (hsz != 0)
+    {
+	HSZNode* pNew = NULL;
+	/* Create a new node for this HSZ.
+	 */
+	pNew = HeapAlloc(GetProcessHeap(), 0, sizeof(HSZNode));
+	if (pNew != NULL)
+	{
+	    pNew->hsz      = hsz;
+	    pNew->next     = pInstance->nodeList;
+	    pNew->refCount = 1;
+	    pInstance->nodeList = pNew;
+	}
+	else
+	{
+	    ERR("Primary HSZ Node allocation failed - out of memory\n");
+	}
+    }
 }
 
-/*****************************************************************
- * DdeUninitialize [USER32.@]  Frees DDEML resources
+/******************************************************************
+ *		WDML_QueryString
  *
- * PARAMS
- *    idInst [I] Instance identifier
  *
- * RETURNS
- *    Success: TRUE
- *    Failure: FALSE
  */
-
-BOOL WINAPI DdeUninitialize(DWORD idInst)
+static int	WDML_QueryString(WDML_INSTANCE* pInstance, HSZ hsz, LPVOID ptr, DWORD cchMax,
+				 int codepage)
 {
-    /*  Stage one - check if we have a handle for this instance
-     */
-    WDML_INSTANCE*		pInstance;
-    WDML_CONV*			pConv;
-    WDML_CONV*			pConvNext;
-
-    TRACE("(%d)\n", idInst);
-
-    /*  First check instance
+    WCHAR	pString[MAX_BUFFER_LEN];
+    int		ret;
+    /* If psz is null, we have to return only the length
+     * of the string.
      */
-    pInstance = WDML_GetInstance(idInst);
-    if (pInstance == NULL)
+    if (ptr == NULL)
     {
-	/*
-	 *	Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
-	 */
-	return FALSE;
+	ptr = pString;
+	cchMax = MAX_BUFFER_LEN;
     }
 
-    /* first terminate all conversations client side
-     * this shall close existing links...
-     */
-    for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv != NULL; pConv = pConvNext)
+    /* if there is no input windows returns a NULL string */
+    if (hsz == NULL)
     {
-	pConvNext = pConv->next;
-	DdeDisconnect((HCONV)pConv);
+	CHAR *t_ptr = ptr;
+	*t_ptr = '\0';
+	return 1;
     }
-    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(pInstance);
-
-    DestroyWindow(pInstance->hwndEvent);
-
-    /* OK now delete the instance handle itself */
 
-    if (WDML_InstanceList == pInstance)
+    switch (codepage)
     {
-	/* special case - the first/only entry */
-	WDML_InstanceList = pInstance->next;
+    case CP_WINANSI:
+	ret = GetAtomNameA(HSZ2ATOM(hsz), ptr, cchMax);
+	break;
+    case CP_WINUNICODE:
+	ret = GetAtomNameW(HSZ2ATOM(hsz), ptr, cchMax);
+        break;
+    default:
+	ERR("Unknown code page %d\n", codepage);
+	ret = 0;
     }
-    else
-    {
-	/* general case, remove entry */
-	WDML_INSTANCE*	inst;
+    return ret;
+}
 
-	for (inst = WDML_InstanceList; inst->next != pInstance; inst = inst->next);
-	inst->next = pInstance->next;
-    }
-    /* release the heap entry
+/*****************************************************************
+ * DdeQueryStringA [USER32.@]
+ */
+DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
+{
+    DWORD		ret = 0;
+    WDML_INSTANCE*	pInstance;
+
+    TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
+
+    /*  First check instance
      */
-    HeapFree(GetProcessHeap(), 0, pInstance);
+    pInstance = WDML_GetInstance(idInst);
+    if (pInstance != NULL)
+    {
+	if (iCodePage == 0) iCodePage = CP_WINANSI;
+	ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
+    }
 
-    return TRUE;
+    TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
+    return ret;
 }
 
-/******************************************************************
- *		WDML_NotifyThreadExit
- *
- *
+/*****************************************************************
+ * DdeQueryStringW [USER32.@]
  */
-void WDML_NotifyThreadDetach(void)
+
+DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
 {
+    DWORD		ret = 0;
     WDML_INSTANCE*	pInstance;
-    WDML_INSTANCE*	next;
-    DWORD		tid = GetCurrentThreadId();
 
-    EnterCriticalSection(&WDML_CritSect);
-    for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = next)
+    TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
+
+    /*  First check instance
+     */
+    pInstance = WDML_GetInstance(idInst);
+    if (pInstance != NULL)
     {
-	next = pInstance->next;
-	if (pInstance->threadID == tid)
-	{
-            LeaveCriticalSection(&WDML_CritSect);
-	    DdeUninitialize(pInstance->instanceID);
-            EnterCriticalSection(&WDML_CritSect);
-	}
+	if (iCodePage == 0) iCodePage = CP_WINUNICODE;
+	ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
     }
-    LeaveCriticalSection(&WDML_CritSect);
+
+    TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
+    return ret;
 }
 
 /******************************************************************
- *		WDML_InvokeCallback
+ *		DML_CreateString
  *
  *
  */
-HDDEDATA 	WDML_InvokeCallback(WDML_INSTANCE* pInstance, UINT uType, UINT uFmt, HCONV hConv,
-				    HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
-				    ULONG_PTR dwData1, ULONG_PTR dwData2)
+static	HSZ	WDML_CreateString(WDML_INSTANCE* pInstance, LPCVOID ptr, int codepage)
 {
-    HDDEDATA	ret;
-
-    if (pInstance == NULL)
-	return NULL;
+    HSZ		hsz;
 
-    TRACE("invoking CB[%p] (%x %x %p %p %p %p %lx %lx)\n",
-	  pInstance->callback, uType, uFmt,
-	  hConv, hsz1, hsz2, hdata, dwData1, dwData2);
-    ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2);
-    TRACE("done => %p\n", ret);
-    return ret;
+    switch (codepage)
+    {
+    case CP_WINANSI:
+	hsz = ATOM2HSZ(AddAtomA(ptr));
+	TRACE("added atom %s with HSZ %p,\n", debugstr_a(ptr), hsz);
+	break;
+    case CP_WINUNICODE:
+	hsz = ATOM2HSZ(AddAtomW(ptr));
+	TRACE("added atom %s with HSZ %p,\n", debugstr_w(ptr), hsz);
+	break;
+    default:
+	ERR("Unknown code page %d\n", codepage);
+	return 0;
+    }
+    WDML_InsertHSZNode(pInstance, hsz);
+    return hsz;
 }
 
-/*****************************************************************************
- *	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
+/*****************************************************************
+ * DdeCreateStringHandleA [USER32.@]
  *
+ * See DdeCreateStringHandleW.
  */
-WDML_INSTANCE*	WDML_GetInstance(DWORD instId)
+HSZ WINAPI DdeCreateStringHandleA(DWORD idInst, LPCSTR psz, INT codepage)
 {
+    HSZ			hsz = 0;
     WDML_INSTANCE*	pInstance;
 
-    EnterCriticalSection(&WDML_CritSect);
+    TRACE("(%d,%s,%d)\n", idInst, debugstr_a(psz), codepage);
 
-    for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = pInstance->next)
+    pInstance = WDML_GetInstance(idInst);
+    if (pInstance == NULL)
+	WDML_SetAllLastError(DMLERR_INVALIDPARAMETER);
+    else
     {
-	if (pInstance->instanceID == instId)
-	{
-	    if (GetCurrentThreadId() != pInstance->threadID)
-	    {
-		FIXME("Tried to get instance from wrong thread\n");
-		continue;
-	    }
-	    break;
-	}
+	if (codepage == 0) codepage = CP_WINANSI;
+	hsz = WDML_CreateString(pInstance, psz, codepage);
     }
 
-    LeaveCriticalSection(&WDML_CritSect);
-
-    if (!pInstance)
-        WARN("Instance entry missing for id %04x\n", instId);
-    return pInstance;
+    return hsz;
 }
 
-/******************************************************************
- *		WDML_GetInstanceFromWnd
- *
- *
- */
-WDML_INSTANCE*	WDML_GetInstanceFromWnd(HWND hWnd)
-{
-    return (WDML_INSTANCE*)GetWindowLongPtrW(hWnd, GWL_WDML_INSTANCE);
-}
 
 /******************************************************************************
- * DdeGetLastError [USER32.@]  Gets most recent error code
+ * DdeCreateStringHandleW [USER32.@]  Creates handle to identify string
  *
  * PARAMS
- *    idInst [I] Instance identifier
- *
+ * 	idInst   [I] Instance identifier
+ * 	psz      [I] Pointer to string
+ *	codepage [I] Code page identifier
  * RETURNS
- *    Last error code
+ *    Success: String handle
+ *    Failure: 0
  */
-UINT WINAPI DdeGetLastError(DWORD idInst)
+HSZ WINAPI DdeCreateStringHandleW(DWORD idInst, LPCWSTR psz, INT codepage)
 {
-    DWORD		error_code;
     WDML_INSTANCE*	pInstance;
+    HSZ			hsz = 0;
 
-    /*  First check instance
-     */
     pInstance = WDML_GetInstance(idInst);
-    if  (pInstance == NULL)
-    {
-	error_code = DMLERR_INVALIDPARAMETER;
-    }
+    if (pInstance == NULL)
+	WDML_SetAllLastError(DMLERR_INVALIDPARAMETER);
     else
     {
-	error_code = pInstance->lastError;
-	pInstance->lastError = 0;
+	if (codepage == 0) codepage = CP_WINUNICODE;
+	hsz = WDML_CreateString(pInstance, psz, codepage);
     }
 
-    return error_code;
+    return hsz;
 }
 
-/******************************************************************
- *		WDML_SetAllLastError
- *
- *
+/*****************************************************************
+ *            DdeFreeStringHandle   (USER32.@)
+ * RETURNS
+ *  success: nonzero
+ *  fail:    zero
  */
-static void	WDML_SetAllLastError(DWORD lastError)
+BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz)
 {
-    DWORD		threadID;
     WDML_INSTANCE*	pInstance;
-    threadID = GetCurrentThreadId();
-    pInstance = WDML_InstanceList;
-    while (pInstance)
-    {
-	if (pInstance->threadID == threadID)
-	    pInstance->lastError = lastError;
-	pInstance = pInstance->next;
-    }
-}
+    BOOL		ret = FALSE;
 
-/* ================================================================
- *
- * 			String management
- *
- * ================================================================ */
+    TRACE("(%d,%p):\n", idInst, hsz);
+
+    /*  First check instance
+     */
+    pInstance = WDML_GetInstance(idInst);
+    if (pInstance)
+	ret = WDML_DecHSZ(pInstance, hsz);
 
+    return ret;
+}
 
-/******************************************************************
- *		WDML_FindNode
- *
+/*****************************************************************
+ *            DdeKeepStringHandle  (USER32.@)
  *
+ * RETURNS
+ *  success: nonzero
+ *  fail:    zero
  */
-static HSZNode*	WDML_FindNode(WDML_INSTANCE* pInstance, HSZ hsz)
+BOOL WINAPI DdeKeepStringHandle(DWORD idInst, HSZ hsz)
 {
-    HSZNode*	pNode;
+    WDML_INSTANCE*	pInstance;
+    BOOL		ret = FALSE;
 
-    if (pInstance == NULL) return NULL;
+    TRACE("(%d,%p):\n", idInst, hsz);
 
-    for (pNode = pInstance->nodeList; pNode != NULL; pNode = pNode->next)
-    {
-	if (pNode->hsz == hsz) break;
-    }
-    if (!pNode) WARN("HSZ %p not found\n", hsz);
-    return pNode;
+    /*  First check instance
+     */
+    pInstance = WDML_GetInstance(idInst);
+    if (pInstance)
+	ret = WDML_IncHSZ(pInstance, hsz);
+
+    return ret;
 }
 
-/******************************************************************
- *		WDML_MakeAtomFromHsz
+/*****************************************************************
+ *            DdeCmpStringHandles (USER32.@)
  *
- * 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(HSZ2ATOM(hsz), nameBuffer, MAX_BUFFER_LEN))
-	return GlobalAddAtomW(nameBuffer);
-    WARN("HSZ %p not 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(const WDML_INSTANCE* pInstance, ATOM atom)
-{
-    WCHAR nameBuffer[MAX_BUFFER_LEN];
-
-    if (!atom) return NULL;
-
-    if (GlobalGetAtomNameW(atom, nameBuffer, MAX_BUFFER_LEN))
-    {
-	TRACE("%x => %s\n", atom, debugstr_w(nameBuffer));
-	return DdeCreateStringHandleW(pInstance->instanceID, nameBuffer, CP_WINUNICODE);
-    }
-    WARN("ATOM 0x%x not found\n", atom);
-    return 0;
-}
-
-/******************************************************************
- *		WDML_IncHSZ
+ * Compares the value of two string handles.  This comparison is
+ * not case sensitive.
  *
+ * PARAMS
+ *  hsz1    [I] Handle to the first string
+ *  hsz2    [I] Handle to the second string
  *
+ * 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
  */
-BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
+INT WINAPI DdeCmpStringHandles(HSZ hsz1, HSZ hsz2)
 {
-    HSZNode*	pNode;
-
-    pNode = WDML_FindNode(pInstance, hsz);
-    if (!pNode) return FALSE;
+    WCHAR	psz1[MAX_BUFFER_LEN];
+    WCHAR	psz2[MAX_BUFFER_LEN];
+    int		ret = 0;
+    int		ret1, ret2;
 
-    pNode->refCount++;
-    return TRUE;
-}
+    ret1 = GetAtomNameW(HSZ2ATOM(hsz1), psz1, MAX_BUFFER_LEN);
+    ret2 = GetAtomNameW(HSZ2ATOM(hsz2), psz2, MAX_BUFFER_LEN);
 
-/******************************************************************************
- *           WDML_DecHSZ    (INTERNAL)
- *
- * Decrease the ref count of an HSZ. If it reaches 0, the node is removed from the list
- * of HSZ nodes
- * Returns -1 is the HSZ isn't found, otherwise it's the current (after --) of the ref count
- */
-BOOL WDML_DecHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
-{
-    HSZNode* 	pPrev = NULL;
-    HSZNode* 	pCurrent;
+    TRACE("(%p<%s> %p<%s>);\n", hsz1, debugstr_w(psz1), hsz2, debugstr_w(psz2));
 
-    for (pCurrent = pInstance->nodeList; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next)
+    /* Make sure we found both strings. */
+    if (ret1 == 0 && ret2 == 0)
     {
-	/* If we found the node we were looking for and its ref count is one,
-	 * we can remove it
+	/* 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 (pCurrent->hsz == hsz)
+	if (ret < 0)
 	{
-	    if (--pCurrent->refCount == 0)
-	    {
-		if (pCurrent == pInstance->nodeList)
-		{
-		    pInstance->nodeList = pCurrent->next;
-		}
-		else
-		{
-		    pPrev->next = pCurrent->next;
-		}
-		HeapFree(GetProcessHeap(), 0, pCurrent);
-		DeleteAtom(HSZ2ATOM(hsz));
-	    }
-	    return TRUE;
+	    ret = -1;
+	}
+	else if (ret > 0)
+	{
+	    ret = 1;
 	}
     }
-    WARN("HSZ %p not found\n", hsz);
 
-    return FALSE;
+    return ret;
 }
 
+/* ================================================================
+ *
+ * 			Instance management
+ *
+ * ================================================================ */
+
 /******************************************************************************
- *            WDML_FreeAllHSZ    (INTERNAL)
+ *		IncrementInstanceId
  *
- * Frees up all the strings still allocated in the list and
- * remove all the nodes from the list of HSZ nodes.
+ *	generic routine to increment the max instance Id and allocate a new application instance
  */
-void WDML_FreeAllHSZ(WDML_INSTANCE* pInstance)
+static void WDML_IncrementInstanceId(WDML_INSTANCE* pInstance)
 {
-    /* Free any strings created in this instance.
-     */
-    while (pInstance->nodeList != NULL)
-    {
-	DdeFreeStringHandle(pInstance->instanceID, pInstance->nodeList->hsz);
-    }
+    DWORD	id = InterlockedIncrement(&WDML_MaxInstanceID);
+
+    pInstance->instanceID = id;
+    TRACE("New instance id %d allocated\n", id);
 }
 
-/******************************************************************************
- *            InsertHSZNode    (INTERNAL)
+/******************************************************************
+ *		WDML_EventProc
+ *
  *
- * Insert a node to the head of the list.
  */
-static void WDML_InsertHSZNode(WDML_INSTANCE* pInstance, HSZ hsz)
+static LRESULT CALLBACK WDML_EventProc(HWND hwndEvent, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
-    if (hsz != 0)
+    WDML_INSTANCE*	pInstance;
+    HSZ			hsz1, hsz2;
+
+    switch (uMsg)
     {
-	HSZNode* pNew = NULL;
-	/* Create a new node for this HSZ.
-	 */
-	pNew = HeapAlloc(GetProcessHeap(), 0, sizeof(HSZNode));
-	if (pNew != NULL)
+    case WM_WDML_REGISTER:
+	pInstance = WDML_GetInstanceFromWnd(hwndEvent);
+        /* try calling the Callback */
+	if (pInstance && !(pInstance->CBFflags & CBF_SKIP_REGISTRATIONS))
 	{
-	    pNew->hsz      = hsz;
-	    pNew->next     = pInstance->nodeList;
-	    pNew->refCount = 1;
-	    pInstance->nodeList = pNew;
+	    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);
 	}
-	else
+	break;
+
+    case WM_WDML_UNREGISTER:
+	pInstance = WDML_GetInstanceFromWnd(hwndEvent);
+	if (pInstance && !(pInstance->CBFflags & CBF_SKIP_UNREGISTRATIONS))
 	{
-	    ERR("Primary HSZ Node allocation failed - out of memory\n");
+	    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
+	     */
+            HWND client = WIN_GetFullHandle( (HWND)wParam );
+            HWND server = WIN_GetFullHandle( (HWND)lParam );
+	    for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConv->next)
+	    {
+		if (pConv->hwndClient == client && pConv->hwndServer == server)
+		    break;
+	    }
+	    if (pConv)
+	    {
+		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 DefWindowProcW(hwndEvent, uMsg, wParam, lParam);
     }
+    return 0;
 }
 
 /******************************************************************
- *		WDML_QueryString
+ *		WDML_Initialize
  *
  *
  */
-static int	WDML_QueryString(WDML_INSTANCE* pInstance, HSZ hsz, LPVOID ptr, DWORD cchMax,
-				 int codepage)
+UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback,
+		     DWORD afCmd, DWORD ulRes, BOOL bUnicode)
 {
-    WCHAR	pString[MAX_BUFFER_LEN];
-    int		ret;
-    /* If psz is null, we have to return only the length
-     * of the string.
-     */
-    if (ptr == NULL)
+    WDML_INSTANCE*		pInstance;
+    WDML_INSTANCE*		reference_inst;
+    UINT			ret;
+    WNDCLASSEXW			wndclass;
+
+    TRACE("(%p,%p,0x%x,%d,0x%x)\n",
+	  pidInst, pfnCallback, afCmd, ulRes, bUnicode);
+
+    if (ulRes)
     {
-	ptr = pString;
-	cchMax = MAX_BUFFER_LEN;
+	ERR("Reserved value not zero?  What does this mean?\n");
+	/* trap this and no more until we know more */
+	return DMLERR_NO_ERROR;
     }
 
-    /* if there is no input windows returns a NULL string */
-    if (hsz == NULL)
+    /* grab enough heap for one control struct - not really necessary for re-initialise
+     *	but allows us to use same validation routines */
+    pInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE));
+    if (pInstance == NULL)
     {
-	CHAR *t_ptr = ptr;
-	*t_ptr = '\0';
-	return 1;
+	/* catastrophe !! warn user & abort */
+	ERR("Instance create failed - out of memory\n");
+	return DMLERR_SYS_ERROR;
     }
+    pInstance->next = NULL;
+    pInstance->monitor = (afCmd | APPCLASS_MONITOR);
 
-    switch (codepage)
-    {
-    case CP_WINANSI:
-	ret = GetAtomNameA(HSZ2ATOM(hsz), ptr, cchMax);
-	break;
-    case CP_WINUNICODE:
-	ret = GetAtomNameW(HSZ2ATOM(hsz), ptr, cchMax);
-        break;
-    default:
-	ERR("Unknown code page %d\n", codepage);
-	ret = 0;
-    }
-    return ret;
-}
+    /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
 
-/*****************************************************************
- * DdeQueryStringA [USER32.@]
- */
-DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
-{
-    DWORD		ret = 0;
-    WDML_INSTANCE*	pInstance;
+    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->nodeList = NULL; /* node will be added later */
+    pInstance->monitorFlags = afCmd & MF_MASK;
+    pInstance->wStatus = 0;
+    pInstance->lastError = DMLERR_NO_ERROR;
+    pInstance->servers = NULL;
+    pInstance->convs[0] = NULL;
+    pInstance->convs[1] = NULL;
+    pInstance->links[0] = NULL;
+    pInstance->links[1] = NULL;
 
-    TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
+    /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
 
-    /*  First check instance
-     */
-    pInstance = WDML_GetInstance(idInst);
-    if (pInstance != NULL)
+    pInstance->CBFflags = afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
+
+    if (!pInstance->clientOnly)
     {
-	if (iCodePage == 0) iCodePage = CP_WINANSI;
-	ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
+	/* Check for other way of setting Client-only !! */
+	pInstance->clientOnly =
+	    (pInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS;
     }
 
-    TRACE("returning %d (%s)\n", ret, debugstr_a(psz));
-    return ret;
-}
+    TRACE("instance created - checking validity\n");
 
-/*****************************************************************
- * DdeQueryStringW [USER32.@]
- */
+    if (*pidInst == 0)
+    {
+	/*  Initialisation of new Instance Identifier */
+	TRACE("new instance, callback %p flags %X\n",pfnCallback,afCmd);
 
-DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
-{
-    DWORD		ret = 0;
-    WDML_INSTANCE*	pInstance;
+	EnterCriticalSection(&WDML_CritSect);
 
-    TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
+	if (WDML_InstanceList == NULL)
+	{
+	    /* can't be another instance in this case, assign to the base pointer */
+	    WDML_InstanceList = pInstance;
 
-    /*  First check instance
-     */
-    pInstance = WDML_GetInstance(idInst);
-    if (pInstance != NULL)
+	    /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
+	     *		present
+	     *	-------------------------------      NOTE NOTE NOTE    --------------------------
+	     *
+	     *	the manual is not clear if this condition
+	     *	applies to the first call to DdeInitialize from an application, or the
+	     *	first call for a given callback !!!
+	     */
+
+	    pInstance->CBFflags = pInstance->CBFflags|APPCMD_FILTERINITS;
+	    TRACE("First application instance detected OK\n");
+	    /*	allocate new instance ID */
+	    WDML_IncrementInstanceId(pInstance);
+	}
+	else
+	{
+	    /* really need to chain the new one in to the latest here, but after checking conditions
+	     *	such as trying to start a conversation from an application trying to monitor */
+	    reference_inst = WDML_InstanceList;
+	    TRACE("Subsequent application instance - starting checks\n");
+	    while (reference_inst->next != NULL)
+	    {
+		/*
+		 *	This set of tests will work if application uses same instance Id
+		 *	at application level once allocated - which is what manual implies
+		 *	should happen. If someone tries to be
+		 *	clever (lazy ?) it will fail to pick up that later calls are for
+		 *	the same application - should we trust them ?
+		 */
+		if (pInstance->instanceID == reference_inst->instanceID)
+		{
+		    /* Check 1 - must be same Client-only state */
+
+		    if (pInstance->clientOnly != reference_inst->clientOnly)
+		    {
+			ret = DMLERR_DLL_USAGE;
+			goto theError;
+		    }
+
+		    /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
+
+		    if (pInstance->monitor != reference_inst->monitor)
+		    {
+			ret = DMLERR_INVALIDPARAMETER;
+			goto theError;
+		    }
+
+		    /* Check 3 - must supply different callback address */
+
+		    if (pInstance->callback == reference_inst->callback)
+		    {
+			ret = DMLERR_DLL_USAGE;
+			goto theError;
+		    }
+		}
+		reference_inst = reference_inst->next;
+	    }
+	    /*  All cleared, add to chain */
+
+	    TRACE("Application Instance checks finished\n");
+	    WDML_IncrementInstanceId(pInstance);
+	    reference_inst->next = pInstance;
+	}
+	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(ULONG_PTR);
+	wndclass.hInstance     = 0;
+	wndclass.hIcon         = 0;
+	wndclass.hCursor       = 0;
+	wndclass.hbrBackground = 0;
+	wndclass.lpszMenuName  = NULL;
+	wndclass.lpszClassName = WDML_szEventClass;
+	wndclass.hIconSm       = 0;
+
+	RegisterClassExW(&wndclass);
+
+	pInstance->hwndEvent = CreateWindowW(WDML_szEventClass, NULL,
+						WS_POPUP, 0, 0, 0, 0,
+						0, 0, 0, 0);
+
+	SetWindowLongPtrW(pInstance->hwndEvent, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance);
+
+	TRACE("New application instance processing finished OK\n");
+    }
+    else
     {
-	if (iCodePage == 0) iCodePage = CP_WINUNICODE;
-	ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
+	/* Reinitialisation situation   --- FIX  */
+	TRACE("reinitialisation of (%p,%p,0x%x,%d): stub\n", pidInst, pfnCallback, afCmd, ulRes);
+
+	EnterCriticalSection(&WDML_CritSect);
+
+	if (WDML_InstanceList == NULL)
+	{
+	    ret = DMLERR_INVALIDPARAMETER;
+	    goto theError;
+	}
+	/* 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 ? */
+	/*
+	 *	MS allows initialisation without specifying a callback, should we allow addition of the
+	 *	callback by a later call to initialise ? - if so this lot will have to change
+	 */
+	while (reference_inst->next != NULL)
+	{
+	    if (*pidInst == reference_inst->instanceID && pfnCallback == reference_inst->callback)
+	    {
+		/* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
+
+		if (reference_inst->clientOnly)
+		{
+		    if  ((reference_inst->CBFflags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
+		    {
+				/* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
+
+			if (!(afCmd & APPCMD_CLIENTONLY))
+			{
+			    ret = DMLERR_INVALIDPARAMETER;
+			    goto theError;
+			}
+		    }
+		}
+		/* Check 2 - cannot change monitor modes */
+
+		if (pInstance->monitor != reference_inst->monitor)
+		{
+		    ret = DMLERR_INVALIDPARAMETER;
+		    goto theError;
+		}
+
+		/* Check 3 - trying to set Client-only via APPCMD when not set so previously */
+
+		if ((afCmd&APPCMD_CLIENTONLY) && !reference_inst->clientOnly)
+		{
+		    ret = DMLERR_INVALIDPARAMETER;
+		    goto theError;
+		}
+		break;
+	    }
+	    reference_inst = reference_inst->next;
+	}
+	if (reference_inst->next == NULL)
+	{
+	    ret = DMLERR_INVALIDPARAMETER;
+	    goto theError;
+	}
+	/* All checked - change relevant flags */
+
+	reference_inst->CBFflags = pInstance->CBFflags;
+	reference_inst->clientOnly = pInstance->clientOnly;
+	reference_inst->monitorFlags = pInstance->monitorFlags;
+
+	HeapFree(GetProcessHeap(), 0, pInstance); /* finished - release heap space used as work store */
+
+	LeaveCriticalSection(&WDML_CritSect);
     }
 
-    TRACE("returning %d (%s)\n", ret, debugstr_w(psz));
+    return DMLERR_NO_ERROR;
+ theError:
+    HeapFree(GetProcessHeap(), 0, pInstance);
+    LeaveCriticalSection(&WDML_CritSect);
     return ret;
 }
 
-/******************************************************************
- *		DML_CreateString
+/******************************************************************************
+ *            DdeInitializeA   (USER32.@)
+ *
+ * See DdeInitializeW.
+ */
+UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback,
+			   DWORD afCmd, DWORD ulRes)
+{
+    return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, 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
  */
-static	HSZ	WDML_CreateString(WDML_INSTANCE* pInstance, LPCVOID ptr, int codepage)
+UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
+			   DWORD afCmd, DWORD ulRes)
 {
-    HSZ		hsz;
-
-    switch (codepage)
-    {
-    case CP_WINANSI:
-	hsz = ATOM2HSZ(AddAtomA(ptr));
-	TRACE("added atom %s with HSZ %p,\n", debugstr_a(ptr), hsz);
-	break;
-    case CP_WINUNICODE:
-	hsz = ATOM2HSZ(AddAtomW(ptr));
-	TRACE("added atom %s with HSZ %p,\n", debugstr_w(ptr), hsz);
-	break;
-    default:
-	ERR("Unknown code page %d\n", codepage);
-	return 0;
-    }
-    WDML_InsertHSZNode(pInstance, hsz);
-    return hsz;
+    return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE);
 }
 
 /*****************************************************************
- * DdeCreateStringHandleA [USER32.@]
+ * DdeUninitialize [USER32.@]  Frees DDEML resources
  *
- * See DdeCreateStringHandleW.
+ * PARAMS
+ *    idInst [I] Instance identifier
+ *
+ * RETURNS
+ *    Success: TRUE
+ *    Failure: FALSE
  */
-HSZ WINAPI DdeCreateStringHandleA(DWORD idInst, LPCSTR psz, INT codepage)
+
+BOOL WINAPI DdeUninitialize(DWORD idInst)
 {
-    HSZ			hsz = 0;
-    WDML_INSTANCE*	pInstance;
+    /*  Stage one - check if we have a handle for this instance
+     */
+    WDML_INSTANCE*		pInstance;
+    WDML_CONV*			pConv;
+    WDML_CONV*			pConvNext;
 
-    TRACE("(%d,%s,%d)\n", idInst, debugstr_a(psz), codepage);
+    TRACE("(%d)\n", idInst);
 
+    /*  First check instance
+     */
     pInstance = WDML_GetInstance(idInst);
     if (pInstance == NULL)
-	WDML_SetAllLastError(DMLERR_INVALIDPARAMETER);
-    else
     {
-	if (codepage == 0) codepage = CP_WINANSI;
-	hsz = WDML_CreateString(pInstance, psz, codepage);
+	/*
+	 *	Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
+	 */
+	return FALSE;
     }
 
-    return hsz;
-}
+    /* 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);
 
-/******************************************************************************
- * 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, LPCWSTR psz, INT codepage)
-{
-    WDML_INSTANCE*	pInstance;
-    HSZ			hsz = 0;
+    /* Free the nodes that were not freed by this instance
+     * and remove the nodes from the list of HSZ nodes.
+     */
+    WDML_FreeAllHSZ(pInstance);
 
-    pInstance = WDML_GetInstance(idInst);
-    if (pInstance == NULL)
-	WDML_SetAllLastError(DMLERR_INVALIDPARAMETER);
+    DestroyWindow(pInstance->hwndEvent);
+
+    /* OK now delete the instance handle itself */
+
+    if (WDML_InstanceList == pInstance)
+    {
+	/* special case - the first/only entry */
+	WDML_InstanceList = pInstance->next;
+    }
     else
     {
-	if (codepage == 0) codepage = CP_WINUNICODE;
-	hsz = WDML_CreateString(pInstance, psz, codepage);
+	/* general case, remove entry */
+	WDML_INSTANCE*	inst;
+
+	for (inst = WDML_InstanceList; inst->next != pInstance; inst = inst->next);
+	inst->next = pInstance->next;
     }
+    /* release the heap entry
+     */
+    HeapFree(GetProcessHeap(), 0, pInstance);
 
-    return hsz;
+    return TRUE;
 }
 
-/*****************************************************************
- *            DdeFreeStringHandle   (USER32.@)
- * RETURNS
- *  success: nonzero
- *  fail:    zero
+/******************************************************************
+ *		WDML_NotifyThreadExit
+ *
+ *
  */
-BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz)
+void WDML_NotifyThreadDetach(void)
 {
     WDML_INSTANCE*	pInstance;
-    BOOL		ret = FALSE;
-
-    TRACE("(%d,%p):\n", idInst, hsz);
-
-    /*  First check instance
-     */
-    pInstance = WDML_GetInstance(idInst);
-    if (pInstance)
-	ret = WDML_DecHSZ(pInstance, hsz);
+    WDML_INSTANCE*	next;
+    DWORD		tid = GetCurrentThreadId();
 
-    return ret;
+    EnterCriticalSection(&WDML_CritSect);
+    for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = next)
+    {
+	next = pInstance->next;
+	if (pInstance->threadID == tid)
+	{
+            LeaveCriticalSection(&WDML_CritSect);
+	    DdeUninitialize(pInstance->instanceID);
+            EnterCriticalSection(&WDML_CritSect);
+	}
+    }
+    LeaveCriticalSection(&WDML_CritSect);
 }
 
-/*****************************************************************
- *            DdeKeepStringHandle  (USER32.@)
+/******************************************************************
+ *		WDML_InvokeCallback
+ *
  *
- * RETURNS
- *  success: nonzero
- *  fail:    zero
  */
-BOOL WINAPI DdeKeepStringHandle(DWORD idInst, HSZ hsz)
+HDDEDATA 	WDML_InvokeCallback(WDML_INSTANCE* pInstance, UINT uType, UINT uFmt, HCONV hConv,
+				    HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
+				    ULONG_PTR dwData1, ULONG_PTR dwData2)
 {
-    WDML_INSTANCE*	pInstance;
-    BOOL		ret = FALSE;
-
-    TRACE("(%d,%p):\n", idInst, hsz);
+    HDDEDATA	ret;
 
-    /*  First check instance
-     */
-    pInstance = WDML_GetInstance(idInst);
-    if (pInstance)
-	ret = WDML_IncHSZ(pInstance, hsz);
+    if (pInstance == NULL)
+	return NULL;
 
+    TRACE("invoking CB[%p] (%x %x %p %p %p %p %lx %lx)\n",
+	  pInstance->callback, uType, uFmt,
+	  hConv, hsz1, hsz2, hdata, dwData1, dwData2);
+    ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2);
+    TRACE("done => %p\n", ret);
     return ret;
 }
 
-/*****************************************************************
- *            DdeCmpStringHandles (USER32.@)
- *
- * Compares the value of two string handles.  This comparison is
- * not case sensitive.
+/*****************************************************************************
+ *	WDML_GetInstance
  *
- * PARAMS
- *  hsz1    [I] Handle to the first string
- *  hsz2    [I] Handle to the second string
+ *	generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
+ *	for an instance Id, or NULL if the entry does not exist
  *
- * 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)
+WDML_INSTANCE*	WDML_GetInstance(DWORD instId)
 {
-    WCHAR	psz1[MAX_BUFFER_LEN];
-    WCHAR	psz2[MAX_BUFFER_LEN];
-    int		ret = 0;
-    int		ret1, ret2;
-
-    ret1 = GetAtomNameW(HSZ2ATOM(hsz1), psz1, MAX_BUFFER_LEN);
-    ret2 = GetAtomNameW(HSZ2ATOM(hsz2), psz2, MAX_BUFFER_LEN);
+    WDML_INSTANCE*	pInstance;
 
-    TRACE("(%p<%s> %p<%s>);\n", hsz1, debugstr_w(psz1), hsz2, debugstr_w(psz2));
+    EnterCriticalSection(&WDML_CritSect);
 
-    /* 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
+    for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = pInstance->next)
     {
-	/* 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)
+	if (pInstance->instanceID == instId)
 	{
-	    ret = 1;
+	    if (GetCurrentThreadId() != pInstance->threadID)
+	    {
+		FIXME("Tried to get instance from wrong thread\n");
+		continue;
+	    }
+	    break;
 	}
     }
 
-    return ret;
+    LeaveCriticalSection(&WDML_CritSect);
+
+    if (!pInstance)
+        WARN("Instance entry missing for id %04x\n", instId);
+    return pInstance;
+}
+
+/******************************************************************
+ *		WDML_GetInstanceFromWnd
+ *
+ *
+ */
+WDML_INSTANCE*	WDML_GetInstanceFromWnd(HWND hWnd)
+{
+    return (WDML_INSTANCE*)GetWindowLongPtrW(hWnd, GWL_WDML_INSTANCE);
 }
 
 /* ================================================================
@@ -1744,8 +1750,261 @@ WDML_SERVER*	WDML_FindServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTo
 	    return pServer;
 	}
     }
-    TRACE("Service name missing\n");
-    return NULL;
+    TRACE("Service name missing\n");
+    return NULL;
+}
+
+/* ================================================================
+ *
+ * 			Link (hot & warm) management
+ *
+ * ================================================================ */
+
+/******************************************************************
+ *		WDML_AddLink
+ *
+ *
+ */
+void WDML_AddLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
+		  UINT wType, HSZ hszItem, UINT wFmt)
+{
+    WDML_LINK*	pLink;
+
+    pLink = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_LINK));
+    if (pLink == NULL)
+    {
+	ERR("OOM\n");
+	return;
+    }
+
+    pLink->hConv = hConv;
+    pLink->transactionType = wType;
+    WDML_IncHSZ(pInstance, pLink->hszItem = hszItem);
+    pLink->uFmt = wFmt;
+    pLink->next = pInstance->links[side];
+    pInstance->links[side] = pLink;
+}
+
+/******************************************************************
+ *		WDML_RemoveLink
+ *
+ *
+ */
+void WDML_RemoveLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
+		     HSZ hszItem, UINT uFmt)
+{
+    WDML_LINK* pPrev = NULL;
+    WDML_LINK* pCurrent = NULL;
+
+    pCurrent = pInstance->links[side];
+
+    while (pCurrent != NULL)
+    {
+	if (pCurrent->hConv == hConv &&
+	    DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
+	    pCurrent->uFmt == uFmt)
+	{
+	    if (pCurrent == pInstance->links[side])
+	    {
+		pInstance->links[side] = pCurrent->next;
+	    }
+	    else
+	    {
+		pPrev->next = pCurrent->next;
+	    }
+
+	    WDML_DecHSZ(pInstance, pCurrent->hszItem);
+	    HeapFree(GetProcessHeap(), 0, pCurrent);
+	    break;
+	}
+
+	pPrev = pCurrent;
+	pCurrent = pCurrent->next;
+    }
+}
+
+/* this function is called to remove all links related to the conv.
+   It should be called from both client and server when terminating
+   the conversation.
+*/
+/******************************************************************
+ *		WDML_RemoveAllLinks
+ *
+ *
+ */
+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 = pInstance->links[side];
+
+    while (pCurrent != NULL)
+    {
+	if (pCurrent->hConv == (HCONV)pConv)
+	{
+	    if (pCurrent == pInstance->links[side])
+	    {
+		pInstance->links[side] = pCurrent->next;
+		pNext = pCurrent->next;
+	    }
+	    else
+	    {
+		pPrev->next = pCurrent->next;
+		pNext = pCurrent->next;
+	    }
+
+	    WDML_DecHSZ(pInstance, pCurrent->hszItem);
+
+	    HeapFree(GetProcessHeap(), 0, pCurrent);
+	    pCurrent = NULL;
+	}
+
+	if (pCurrent)
+	{
+	    pPrev = pCurrent;
+	    pCurrent = pCurrent->next;
+	}
+	else
+	{
+	    pCurrent = pNext;
+	}
+    }
+}
+
+/******************************************************************
+ *		WDML_FindLink
+ *
+ *
+ */
+WDML_LINK* 	WDML_FindLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
+			      HSZ hszItem, BOOL use_fmt, UINT uFmt)
+{
+    WDML_LINK*	pCurrent = NULL;
+
+    for (pCurrent = pInstance->links[side]; pCurrent != NULL; pCurrent = pCurrent->next)
+    {
+	/* we don't need to check for transaction type as it can be altered */
+
+	if (pCurrent->hConv == hConv &&
+	    DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
+	    (!use_fmt || pCurrent->uFmt == uFmt))
+	{
+	    break;
+	}
+
+    }
+
+    return pCurrent;
+}
+
+/* ================================================================
+ *
+ * 			Transaction management
+ *
+ * ================================================================ */
+
+/******************************************************************
+ *		WDML_AllocTransaction
+ *
+ * Alloc a transaction structure for handling the message ddeMsg
+ */
+WDML_XACT*	WDML_AllocTransaction(WDML_INSTANCE* pInstance, UINT ddeMsg,
+				      UINT wFmt, HSZ hszItem)
+{
+    WDML_XACT*		pXAct;
+    static WORD		tid = 1;	/* FIXME: wrap around */
+
+    pXAct = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_XACT));
+    if (!pXAct)
+    {
+	pInstance->lastError = DMLERR_MEMORY_ERROR;
+	return NULL;
+    }
+
+    pXAct->xActID = tid++;
+    pXAct->ddeMsg = ddeMsg;
+    pXAct->hDdeData = 0;
+    pXAct->hUser = 0;
+    pXAct->next = NULL;
+    pXAct->wType = 0;
+    pXAct->wFmt = wFmt;
+    if ((pXAct->hszItem = hszItem)) WDML_IncHSZ(pInstance, pXAct->hszItem);
+    pXAct->atom = 0;
+    pXAct->hMem = 0;
+    pXAct->lParam = 0;
+
+    return pXAct;
+}
+
+/******************************************************************
+ *		WDML_QueueTransaction
+ *
+ * Adds a transaction to the list of transaction
+ */
+void	WDML_QueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct)
+{
+    WDML_XACT**	pt;
+
+    /* advance to last in queue */
+    for (pt = &pConv->transactions; *pt != NULL; pt = &(*pt)->next);
+    *pt = pXAct;
+}
+
+/******************************************************************
+ *		WDML_UnQueueTransaction
+ *
+ *
+ */
+BOOL	WDML_UnQueueTransaction(WDML_CONV* pConv, WDML_XACT*  pXAct)
+{
+    WDML_XACT**	pt;
+
+    for (pt = &pConv->transactions; *pt; pt = &(*pt)->next)
+    {
+	if (*pt == pXAct)
+	{
+	    *pt = pXAct->next;
+	    return TRUE;
+	}
+    }
+    return FALSE;
+}
+
+/******************************************************************
+ *		WDML_FreeTransaction
+ *
+ *
+ */
+void	WDML_FreeTransaction(WDML_INSTANCE* pInstance, WDML_XACT* pXAct, BOOL doFreePmt)
+{
+    /* free pmt(s) in pXAct too. check against one for not deleting TRUE return values */
+    if (doFreePmt && (ULONG_PTR)pXAct->hMem > 1)
+    {
+	GlobalFree(pXAct->hMem);
+    }
+    if (pXAct->hszItem) WDML_DecHSZ(pInstance, pXAct->hszItem);
+
+    HeapFree(GetProcessHeap(), 0, pXAct);
+}
+
+/******************************************************************
+ *		WDML_FindTransaction
+ *
+ *
+ */
+WDML_XACT*	WDML_FindTransaction(WDML_CONV* pConv, DWORD tid)
+{
+    WDML_XACT* pXAct;
+
+    tid = HIWORD(tid);
+    for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next)
+    {
+	if (pXAct->xActID == tid)
+	    break;
+    }
+    return pXAct;
 }
 
 /* ================================================================
@@ -2215,259 +2474,6 @@ UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, PCONVINFO lpConvInfo)
 
 /* ================================================================
  *
- * 			Link (hot & warm) management
- *
- * ================================================================ */
-
-/******************************************************************
- *		WDML_AddLink
- *
- *
- */
-void WDML_AddLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
-		  UINT wType, HSZ hszItem, UINT wFmt)
-{
-    WDML_LINK*	pLink;
-
-    pLink = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_LINK));
-    if (pLink == NULL)
-    {
-	ERR("OOM\n");
-	return;
-    }
-
-    pLink->hConv = hConv;
-    pLink->transactionType = wType;
-    WDML_IncHSZ(pInstance, pLink->hszItem = hszItem);
-    pLink->uFmt = wFmt;
-    pLink->next = pInstance->links[side];
-    pInstance->links[side] = pLink;
-}
-
-/******************************************************************
- *		WDML_RemoveLink
- *
- *
- */
-void WDML_RemoveLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
-		     HSZ hszItem, UINT uFmt)
-{
-    WDML_LINK* pPrev = NULL;
-    WDML_LINK* pCurrent = NULL;
-
-    pCurrent = pInstance->links[side];
-
-    while (pCurrent != NULL)
-    {
-	if (pCurrent->hConv == hConv &&
-	    DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
-	    pCurrent->uFmt == uFmt)
-	{
-	    if (pCurrent == pInstance->links[side])
-	    {
-		pInstance->links[side] = pCurrent->next;
-	    }
-	    else
-	    {
-		pPrev->next = pCurrent->next;
-	    }
-
-	    WDML_DecHSZ(pInstance, pCurrent->hszItem);
-	    HeapFree(GetProcessHeap(), 0, pCurrent);
-	    break;
-	}
-
-	pPrev = pCurrent;
-	pCurrent = pCurrent->next;
-    }
-}
-
-/* this function is called to remove all links related to the conv.
-   It should be called from both client and server when terminating
-   the conversation.
-*/
-/******************************************************************
- *		WDML_RemoveAllLinks
- *
- *
- */
-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 = pInstance->links[side];
-
-    while (pCurrent != NULL)
-    {
-	if (pCurrent->hConv == (HCONV)pConv)
-	{
-	    if (pCurrent == pInstance->links[side])
-	    {
-		pInstance->links[side] = pCurrent->next;
-		pNext = pCurrent->next;
-	    }
-	    else
-	    {
-		pPrev->next = pCurrent->next;
-		pNext = pCurrent->next;
-	    }
-
-	    WDML_DecHSZ(pInstance, pCurrent->hszItem);
-
-	    HeapFree(GetProcessHeap(), 0, pCurrent);
-	    pCurrent = NULL;
-	}
-
-	if (pCurrent)
-	{
-	    pPrev = pCurrent;
-	    pCurrent = pCurrent->next;
-	}
-	else
-	{
-	    pCurrent = pNext;
-	}
-    }
-}
-
-/******************************************************************
- *		WDML_FindLink
- *
- *
- */
-WDML_LINK* 	WDML_FindLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side,
-			      HSZ hszItem, BOOL use_fmt, UINT uFmt)
-{
-    WDML_LINK*	pCurrent = NULL;
-
-    for (pCurrent = pInstance->links[side]; pCurrent != NULL; pCurrent = pCurrent->next)
-    {
-	/* we don't need to check for transaction type as it can be altered */
-
-	if (pCurrent->hConv == hConv &&
-	    DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 &&
-	    (!use_fmt || pCurrent->uFmt == uFmt))
-	{
-	    break;
-	}
-
-    }
-
-    return pCurrent;
-}
-
-/* ================================================================
- *
- * 			Transaction management
- *
- * ================================================================ */
-
-/******************************************************************
- *		WDML_AllocTransaction
- *
- * Alloc a transaction structure for handling the message ddeMsg
- */
-WDML_XACT*	WDML_AllocTransaction(WDML_INSTANCE* pInstance, UINT ddeMsg,
-				      UINT wFmt, HSZ hszItem)
-{
-    WDML_XACT*		pXAct;
-    static WORD		tid = 1;	/* FIXME: wrap around */
-
-    pXAct = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_XACT));
-    if (!pXAct)
-    {
-	pInstance->lastError = DMLERR_MEMORY_ERROR;
-	return NULL;
-    }
-
-    pXAct->xActID = tid++;
-    pXAct->ddeMsg = ddeMsg;
-    pXAct->hDdeData = 0;
-    pXAct->hUser = 0;
-    pXAct->next = NULL;
-    pXAct->wType = 0;
-    pXAct->wFmt = wFmt;
-    if ((pXAct->hszItem = hszItem)) WDML_IncHSZ(pInstance, pXAct->hszItem);
-    pXAct->atom = 0;
-    pXAct->hMem = 0;
-    pXAct->lParam = 0;
-
-    return pXAct;
-}
-
-/******************************************************************
- *		WDML_QueueTransaction
- *
- * Adds a transaction to the list of transaction
- */
-void	WDML_QueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct)
-{
-    WDML_XACT**	pt;
-
-    /* advance to last in queue */
-    for (pt = &pConv->transactions; *pt != NULL; pt = &(*pt)->next);
-    *pt = pXAct;
-}
-
-/******************************************************************
- *		WDML_UnQueueTransaction
- *
- *
- */
-BOOL	WDML_UnQueueTransaction(WDML_CONV* pConv, WDML_XACT*  pXAct)
-{
-    WDML_XACT**	pt;
-
-    for (pt = &pConv->transactions; *pt; pt = &(*pt)->next)
-    {
-	if (*pt == pXAct)
-	{
-	    *pt = pXAct->next;
-	    return TRUE;
-	}
-    }
-    return FALSE;
-}
-
-/******************************************************************
- *		WDML_FreeTransaction
- *
- *
- */
-void	WDML_FreeTransaction(WDML_INSTANCE* pInstance, WDML_XACT* pXAct, BOOL doFreePmt)
-{
-    /* free pmt(s) in pXAct too. check against one for not deleting TRUE return values */
-    if (doFreePmt && (ULONG_PTR)pXAct->hMem > 1)
-    {
-	GlobalFree(pXAct->hMem);
-    }
-    if (pXAct->hszItem) WDML_DecHSZ(pInstance, pXAct->hszItem);
-
-    HeapFree(GetProcessHeap(), 0, pXAct);
-}
-
-/******************************************************************
- *		WDML_FindTransaction
- *
- *
- */
-WDML_XACT*	WDML_FindTransaction(WDML_CONV* pConv, DWORD tid)
-{
-    WDML_XACT* pXAct;
-
-    tid = HIWORD(tid);
-    for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next)
-    {
-	if (pXAct->xActID == tid)
-	    break;
-    }
-    return pXAct;
-}
-
-/* ================================================================
- *
  * 	   Information broadcast across DDEML implementations
  *
  * ================================================================ */
-- 
1.7.10




More information about the wine-patches mailing list