+ 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;