static WDML_INSTANCE* WDML_InstanceList = NULL;
static LONG WDML_MaxInstanceID = 0; /* OK for present, have to worry about wrap-around later */
-const WCHAR WDML_szEventClass[] = {'D','d','e','E','v','e','n','t','C','l','a','s','s',0};
+const WCHAR WDML_szEventClass[] = {'D','D','E','M','L','E','v','e','n','t',0};
/* protection for instance list */
CRITICAL_SECTION WDML_CritSect;
return uiHi;
default:
- return MAKELPARAM(uiLo, uiHi);
+ return MAKELONG(uiLo, uiHi);
}
}
* DdeSetQualityOfService (USER32.@)
*/
-BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
+BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, const SECURITY_QUALITY_OF_SERVICE *pqosNew,
PSECURITY_QUALITY_OF_SERVICE pqosPrev)
{
FIXME("(%p %p %p): stub\n", hwndClient, pqosNew, pqosPrev);
/* ================================================================
*
- * 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 = (HWND)wParam;
- HWND server = (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)
+ if (pCurrent == pInstance->nodeList)
{
- /* 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)
- {
- 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
+ WCHAR pString[MAX_BUFFER_LEN];
+ int ret;
+ /* If psz is null, we have to return only the length
+ * of the string.
*/
- WDML_INSTANCE* pInstance;
- WDML_CONV* pConv;
- WDML_CONV* pConvNext;
-
- TRACE("(%d)\n", idInst);
+ if (ptr == NULL)
+ {
+ ptr = pString;
+ cchMax = MAX_BUFFER_LEN;
+ }
- /* First check instance
- */
- pInstance = WDML_GetInstance(idInst);
- if (pInstance == NULL)
+ /* if there is no input windows returns a NULL string */
+ if (hsz == NULL)
{
- /*
- * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
- */
- return FALSE;
+ CHAR *t_ptr = ptr;
+ *t_ptr = '\0';
+ return 1;
}
- /* first terminate all conversations client side
- * this shall close existing links...
- */
- for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv != NULL; pConv = pConvNext)
+ switch (codepage)
{
- pConvNext = pConv->next;
- DdeDisconnect((HCONV)pConv);
+ 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;
}
- if (pInstance->convs[WDML_CLIENT_SIDE])
- FIXME("still pending conversations\n");
+ return ret;
+}
- /* then unregister all known service names */
- DdeNameService(idInst, 0, 0, DNS_UNREGISTER);
+/*****************************************************************
+ * DdeQueryStringA [USER32.@]
+ */
+DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
+{
+ DWORD ret = 0;
+ WDML_INSTANCE* pInstance;
- /* 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 */
+ TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
- if (WDML_InstanceList == pInstance)
- {
- /* special case - the first/only entry */
- WDML_InstanceList = pInstance->next;
- }
- else
+ /* First check instance
+ */
+ pInstance = WDML_GetInstance(idInst);
+ if (pInstance != NULL)
{
- /* general case, remove entry */
- WDML_INSTANCE* inst;
-
- for (inst = WDML_InstanceList; inst->next != pInstance; inst = inst->next);
- inst->next = pInstance->next;
+ if (iCodePage == 0) iCodePage = CP_WINANSI;
+ ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage);
}
- /* release the heap entry
- */
- HeapFree(GetProcessHeap(), 0, pInstance);
- 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
+ * 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
*/
-ATOM WDML_MakeAtomFromHsz(HSZ hsz)
+INT WINAPI DdeCmpStringHandles(HSZ hsz1, HSZ hsz2)
{
- WCHAR nameBuffer[MAX_BUFFER_LEN];
+ WCHAR psz1[MAX_BUFFER_LEN];
+ WCHAR psz2[MAX_BUFFER_LEN];
+ int ret = 0;
+ int ret1, ret2;
- 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];
+ ret1 = GetAtomNameW(HSZ2ATOM(hsz1), psz1, MAX_BUFFER_LEN);
+ ret2 = GetAtomNameW(HSZ2ATOM(hsz2), psz2, MAX_BUFFER_LEN);
- if (!atom) return NULL;
+ TRACE("(%p<%s> %p<%s>);\n", hsz1, debugstr_w(psz1), hsz2, debugstr_w(psz2));
- if (GlobalGetAtomNameW(atom, nameBuffer, MAX_BUFFER_LEN))
+ /* Make sure we found both strings. */
+ if (ret1 == 0 && ret2 == 0)
{
- TRACE("%x => %s\n", atom, debugstr_w(nameBuffer));
- return DdeCreateStringHandleW(pInstance->instanceID, nameBuffer, CP_WINUNICODE);
+ /* If both are not found, return both "zero strings". */
+ ret = 0;
}
- WARN("ATOM 0x%x not found\n", atom);
- return 0;
-}
-
-/******************************************************************
- * WDML_IncHSZ
- *
- *
- */
-BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
-{
- HSZNode* pNode;
-
- pNode = WDML_FindNode(pInstance, hsz);
- if (!pNode) return FALSE;
-
- pNode->refCount++;
- return TRUE;
-}
-
-/******************************************************************************
- * WDML_DecHSZ (INTERNAL)
- *
- * Decrease the ref count of an HSZ. If it reaches 0, the node is removed from the list
- * of HSZ nodes
- * Returns -1 is the HSZ isn't found, otherwise it's the current (after --) of the ref count
- */
-BOOL WDML_DecHSZ(WDML_INSTANCE* pInstance, HSZ hsz)
-{
- HSZNode* pPrev = NULL;
- HSZNode* pCurrent;
-
- for (pCurrent = pInstance->nodeList; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next)
+ else if (ret1 == 0)
{
- /* If we found the node we were looking for and its ref count is one,
- * we can remove it
+ /* 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 = (HWND)wParam;
+ HWND server = (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)
- {
- ptr = pString;
- cchMax = MAX_BUFFER_LEN;
- }
+ WDML_INSTANCE* pInstance;
+ WDML_INSTANCE* reference_inst;
+ UINT ret;
+ WNDCLASSEXW wndclass;
- /* if there is no input windows returns a NULL string */
- if (hsz == NULL)
+ TRACE("(%p,%p,0x%x,%d,0x%x)\n",
+ pidInst, pfnCallback, afCmd, ulRes, bUnicode);
+
+ if (ulRes)
{
- CHAR *t_ptr = ptr;
- *t_ptr = '\0';
- return 1;
+ ERR("Reserved value not zero? What does this mean?\n");
+ /* trap this and no more until we know more */
+ return DMLERR_INVALIDPARAMETER;
}
- switch (codepage)
+ /* 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)
{
- 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;
+ /* catastrophe !! warn user & abort */
+ ERR("Instance create failed - out of memory\n");
+ return DMLERR_SYS_ERROR;
}
- return ret;
-}
+ pInstance->next = NULL;
+ pInstance->monitor = (afCmd | APPCLASS_MONITOR);
-/*****************************************************************
- * DdeQueryStringA [USER32.@]
- */
-DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
-{
- DWORD ret = 0;
- WDML_INSTANCE* pInstance;
+ /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
- TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage);
+ 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;
- /* First check instance
- */
- pInstance = WDML_GetInstance(idInst);
- if (pInstance != NULL)
+ /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
+
+ 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;
-}
+ ERR("instance created - checking validity\n");
-/*****************************************************************
- * DdeQueryStringW [USER32.@]
- */
+ if (*pidInst == 0)
+ {
+ /* Initialisation of new Instance Identifier */
+ ERR("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;
+ ERR("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;
+ ERR("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)
+ {
+ ERR("WDML_Initialize Mustbe Client-only\n");
+ ret = DMLERR_DLL_USAGE;
+ goto theError;
+ }
+
+ /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
+
+ if (pInstance->monitor != reference_inst->monitor)
+ {
+ ERR("WDML_Initialize cannot use monitor w/any modes\n");
+ 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 */
+
+ ERR("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);
+
+ ERR("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 */
+ ERR("reinitialisation of (%p,%p,0x%x,%d): stub\n", pidInst, pfnCallback, afCmd, ulRes);
+
+ EnterCriticalSection(&WDML_CritSect);
+
+ if (WDML_InstanceList == NULL)
+ {
+ ERR("WDML_Initialize No instance list\n");
+ 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))
+ {
+ ERR("WDML_Initialize AppCmd Client-only 2\n");
+ ret = DMLERR_INVALIDPARAMETER;
+ goto theError;
+ }
+ }
+ }
+ /* Check 2 - cannot change monitor modes */
+
+ if (pInstance->monitor != reference_inst->monitor)
+ {
+ ERR("WDML_Initialize cannot change monitor modes 2\n");
+ 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)
+ {
+ ERR("WDML_Initialize trying to set Client-only via APPCMD\n");
+ ret = DMLERR_INVALIDPARAMETER;
+ goto theError;
+ }
+ break;
+ }
+ reference_inst = reference_inst->next;
+ }
+ if (reference_inst->next == NULL)
+ {
+ ERR("WDML_Initialize Nothing Next\n");
+ 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:
+ ERR("WDML_Initialize error %x\n",ret);
+ 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);
}
/* ================================================================
/* 1 is the handle value returned by an asynchronous operation. */
if (hData == (HDDEDATA)1)
- return TRUE;
+ return TRUE;
return GlobalFree(hData) == 0;
}
default:
FIXME("Unsupported format (%04x) for data %p, passing raw information\n",
pDd->cfFormat, hMem);
- /* fall thru */
+ /* fall through */
case 0:
case CF_TEXT:
ret = DdeCreateDataHandle(pConv->instance->instanceID, pDd->Value, size, 0, 0, pDd->cfFormat, 0);
default:
FIXME("Unsupported format (%04x) for data %p, passing raw information\n",
pDdh->cfFormat, hDdeData);
- /* fall thru */
+ /* fall through */
case 0:
case CF_TEXT:
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(WINE_DDEHEAD) + dwSize);
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;
}
/* ================================================================
}
if (wCmd == EC_QUERYWAITING)
- return pConv->transactions ? TRUE : FALSE;
+ return pConv->transactions != NULL;
if (wCmd != EC_ENABLEALL && wCmd != EC_ENABLEONE)
{
return ret;
}
-/* ================================================================
- *
- * 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