📄 dde.c
字号:
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%lx,%ld): stub\n", pidInst, pfnCallback, afCmd, ulRes);
EnterCriticalSection(&WDML_CritSect);
if (WDML_InstanceList == NULL)
{
ret = DMLERR_INVALIDPARAMETER;
goto theError;
}
HeapFree(GetProcessHeap(), 0, pInstance); /* finished - release heap space used as work store */
/* can't reinitialise if we have initialised nothing !! */
reference_inst = WDML_InstanceList;
/* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
/*
* 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;
LeaveCriticalSection(&WDML_CritSect);
}
return DMLERR_NO_ERROR;
theError:
HeapFree(GetProcessHeap(), 0, pInstance);
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/******************************************************************************
* DdeInitializeA (USER32.@)
*
* See DdeInitializeW.
*/
UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes)
{
return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, FALSE, FALSE);
}
/******************************************************************************
* DdeInitializeW [USER32.@]
* Registers an application with the DDEML
*
* PARAMS
* pidInst [I] Pointer to instance identifier
* pfnCallback [I] Pointer to callback function
* afCmd [I] Set of command and filter flags
* ulRes [I] Reserved
*
* RETURNS
* Success: DMLERR_NO_ERROR
* Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
*/
UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback,
DWORD afCmd, DWORD ulRes)
{
return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE, FALSE);
}
/*****************************************************************
* DdeUninitialize [USER32.@] Frees DDEML resources
*
* PARAMS
* idInst [I] Instance identifier
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI DdeUninitialize(DWORD idInst)
{
/* Stage one - check if we have a handle for this instance
*/
WDML_INSTANCE* pInstance;
WDML_CONV* pConv;
WDML_CONV* pConvNext;
TRACE("(%ld)\n", idInst);
EnterCriticalSection(&WDML_CritSect);
/* First check instance
*/
pInstance = WDML_GetInstance(idInst);
if (pInstance == NULL)
{
LeaveCriticalSection(&WDML_CritSect);
/*
* Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
*/
return FALSE;
}
/* first terminate all conversations client side
* this shall close existing links...
*/
for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv != NULL; pConv = pConvNext)
{
pConvNext = pConv->next;
DdeDisconnect((HCONV)pConv);
}
if (pInstance->convs[WDML_CLIENT_SIDE])
FIXME("still pending conversations\n");
/* then unregister all known service names */
DdeNameService(idInst, 0, 0, DNS_UNREGISTER);
/* Free the nodes that were not freed by this instance
* and remove the nodes from the list of HSZ nodes.
*/
WDML_FreeAllHSZ(pInstance);
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
{
/* general case, remove entry */
WDML_INSTANCE* inst;
for (inst = WDML_InstanceList; inst->next != pInstance; inst = inst->next);
inst->next = pInstance->next;
}
/* leave crit sect and release the heap entry
*/
HeapFree(GetProcessHeap(), 0, pInstance);
LeaveCriticalSection(&WDML_CritSect);
return TRUE;
}
/******************************************************************
* WDML_NotifyThreadExit
*
*
*/
void WDML_NotifyThreadDetach(void)
{
WDML_INSTANCE* pInstance;
WDML_INSTANCE* next;
DWORD tid = GetCurrentThreadId();
EnterCriticalSection(&WDML_CritSect);
for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = next)
{
next = pInstance->next;
if (pInstance->threadID == tid)
{
DdeUninitialize(pInstance->instanceID);
}
}
LeaveCriticalSection(&WDML_CritSect);
}
/******************************************************************
* WDML_InvokeCallback
*
*
*/
HDDEDATA WDML_InvokeCallback(WDML_INSTANCE* pInstance, UINT uType, UINT uFmt, HCONV hConv,
HSZ hsz1, HSZ hsz2, HDDEDATA hdata,
ULONG_PTR dwData1, ULONG_PTR dwData2)
{
HDDEDATA ret;
if (pInstance == NULL)
return NULL;
TRACE("invoking CB%d[%p] (%x %x %p %p %p %p %lx %lx)\n",
pInstance->win16 ? 16 : 32, 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;
}
/*****************************************************************************
* WDML_GetInstance
*
* generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
* for an instance Id, or NULL if the entry does not exist
*
*/
WDML_INSTANCE* WDML_GetInstance(DWORD instId)
{
WDML_INSTANCE* pInstance;
for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = pInstance->next)
{
if (pInstance->instanceID == instId)
{
if (GetCurrentThreadId() != pInstance->threadID)
{
FIXME("Tried to get instance from wrong thread\n");
continue;
}
return pInstance;
}
}
TRACE("Instance entry missing\n");
return NULL;
}
/******************************************************************
* WDML_GetInstanceFromWnd
*
*
*/
WDML_INSTANCE* WDML_GetInstanceFromWnd(HWND hWnd)
{
return (WDML_INSTANCE*)GetWindowLongPtrW(hWnd, GWL_WDML_INSTANCE);
}
/******************************************************************************
* DdeGetLastError [USER32.@] Gets most recent error code
*
* PARAMS
* idInst [I] Instance identifier
*
* RETURNS
* Last error code
*/
UINT WINAPI DdeGetLastError(DWORD idInst)
{
DWORD error_code;
WDML_INSTANCE* pInstance;
EnterCriticalSection(&WDML_CritSect);
/* First check instance
*/
pInstance = WDML_GetInstance(idInst);
if (pInstance == NULL)
{
error_code = DMLERR_INVALIDPARAMETER;
}
else
{
error_code = pInstance->lastError;
pInstance->lastError = 0;
}
LeaveCriticalSection(&WDML_CritSect);
return error_code;
}
/* ================================================================
*
* String management
*
* ================================================================ */
/******************************************************************
* WDML_FindNode
*
*
*/
static HSZNode* WDML_FindNode(WDML_INSTANCE* pInstance, HSZ hsz)
{
HSZNode* pNode;
if (pInstance == NULL) return NULL;
for (pNode = pInstance->nodeList; pNode != NULL; pNode = pNode->next)
{
if (pNode->hsz == hsz) break;
}
if (!pNode) WARN("HSZ %p not found\n", hsz);
return pNode;
}
/******************************************************************
* WDML_MakeAtomFromHsz
*
* Creates a global atom from an existing HSZ
* Generally used before sending an HSZ as an atom to a remote app
*/
ATOM WDML_MakeAtomFromHsz(HSZ hsz)
{
WCHAR nameBuffer[MAX_BUFFER_LEN];
if (GetAtomNameW(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(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
*
*
*/
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)
{
/* If we found the node we were looking for and its ref count is one,
* we can remove it
*/
if (pCurrent->hsz == hsz)
{
if (--pCurrent->refCount == 0)
{
if (pCurrent == pInstance->nodeList)
{
pInstance->nodeList = pCurrent->next;
}
else
{
pPrev->next = pCurrent->next;
}
HeapFree(GetProcessHeap(), 0, pCurrent);
DeleteAtom(HSZ2ATOM(hsz));
}
return TRUE;
}
}
WARN("HSZ %p not found\n", hsz);
return FALSE;
}
/******************************************************************************
* WDML_FreeAllHSZ (INTERNAL)
*
* Frees up all the strings still allocated in the list and
* remove all the nodes from the list of HSZ nodes.
*/
void WDML_FreeAllHSZ(WDML_INSTANCE* pInstance)
{
/* Free any strings created in this instance.
*/
while (pInstance->nodeList != NULL)
{
DdeFreeStringHandle(pInstance->instanceID, pInstance->nodeList->hsz);
}
}
/******************************************************************************
* InsertHSZNode (INTERNAL)
*
* Insert a node to the head of the list.
*/
static void WDML_InsertHSZNode(WDML_INSTANCE* pInstance, HSZ hsz)
{
if (hsz != 0)
{
HSZNode* pNew = NULL;
/* Create a new node for this HSZ.
*/
pNew = (HSZNode*)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");
}
}
}
/******************************************************************
* WDML_QueryString
*
*
*/
static int WDML_QueryString(WDML_INSTANCE* pInstance, HSZ hsz, LPVOID ptr, DWORD cchMax,
int codepage)
{
WCHAR pString[MAX_BUFFER_LEN];
int ret;
/* If psz is null, we have to return only the length
* of the string.
*/
if (ptr == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -