📄 dde.c
字号:
if (side == WDML_SERVER_SIDE)
{
from = pConv->hwndServer;
to = pConv->hwndClient;
}
else
{
to = pConv->hwndServer;
from = pConv->hwndClient;
}
ddeAck.bAppReturnCode = appRetCode;
ddeAck.reserved = 0;
ddeAck.fBusy = fBusy;
ddeAck.fAck = fAck;
TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative");
lParam = (lParam) ? ReuseDDElParam(lParam, oldMsg, WM_DDE_ACK, *(WORD*)&ddeAck, pmt) :
PackDDElParam(WM_DDE_ACK, *(WORD*)&ddeAck, pmt);
if (!PostMessageW(to, WM_DDE_ACK, (WPARAM)from, lParam))
{
pConv->wStatus &= ~ST_CONNECTED;
FreeDDElParam(WM_DDE_ACK, lParam);
return FALSE;
}
return TRUE;
}
/*****************************************************************
* DdeSetUserHandle (USER32.@)
*/
BOOL WINAPI DdeSetUserHandle(HCONV hConv, DWORD id, DWORD hUser)
{
WDML_CONV* pConv;
BOOL ret = TRUE;
TRACE("(%p,%lx,%lx)\n", hConv, id, hUser);
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv == NULL)
{
ret = FALSE;
goto theError;
}
if (id == QID_SYNC)
{
pConv->hUser = hUser;
}
else
{
WDML_XACT* pXAct;
pXAct = WDML_FindTransaction(pConv, id);
if (pXAct)
{
pXAct->hUser = hUser;
}
else
{
pConv->instance->lastError = DMLERR_UNFOUND_QUEUE_ID;
ret = FALSE;
}
}
theError:
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/******************************************************************
* WDML_GetLocalConvInfo
*
*
*/
static BOOL WDML_GetLocalConvInfo(WDML_CONV* pConv, CONVINFO* ci, DWORD id)
{
BOOL ret = TRUE;
WDML_LINK* pLink;
WDML_SIDE side;
ci->hConvPartner = (pConv->wStatus & ST_ISLOCAL) ? (HCONV)((ULONG_PTR)pConv | 1) : 0;
ci->hszSvcPartner = pConv->hszService;
ci->hszServiceReq = pConv->hszService; /* FIXME: they shouldn't be the same, should they ? */
ci->hszTopic = pConv->hszTopic;
ci->wStatus = pConv->wStatus;
side = (pConv->wStatus & ST_CLIENT) ? WDML_CLIENT_SIDE : WDML_SERVER_SIDE;
for (pLink = pConv->instance->links[side]; pLink != NULL; pLink = pLink->next)
{
if (pLink->hConv == (HCONV)pConv)
{
ci->wStatus |= ST_ADVISE;
break;
}
}
/* FIXME: non handled status flags:
ST_BLOCKED
ST_BLOCKNEXT
ST_INLIST
*/
ci->wConvst = pConv->wConvst; /* FIXME */
ci->wLastError = 0; /* FIXME: note it's not the instance last error */
ci->hConvList = 0;
ci->ConvCtxt = pConv->convContext;
if (ci->wStatus & ST_CLIENT)
{
ci->hwnd = pConv->hwndClient;
ci->hwndPartner = pConv->hwndServer;
}
else
{
ci->hwnd = pConv->hwndServer;
ci->hwndPartner = pConv->hwndClient;
}
if (id == QID_SYNC)
{
ci->hUser = pConv->hUser;
ci->hszItem = 0;
ci->wFmt = 0;
ci->wType = 0;
}
else
{
WDML_XACT* pXAct;
pXAct = WDML_FindTransaction(pConv, id);
if (pXAct)
{
ci->hUser = pXAct->hUser;
ci->hszItem = pXAct->hszItem;
ci->wFmt = pXAct->wFmt;
ci->wType = pXAct->wType;
}
else
{
ret = 0;
pConv->instance->lastError = DMLERR_UNFOUND_QUEUE_ID;
}
}
return ret;
}
/******************************************************************
* DdeQueryConvInfo (USER32.@)
*
* FIXME: Set last DDE error on failure.
*/
UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, PCONVINFO lpConvInfo)
{
UINT ret = lpConvInfo->cb;
CONVINFO ci;
WDML_CONV* pConv;
TRACE("(%p,%lx,%p)\n", hConv, id, lpConvInfo);
if (!hConv)
{
FIXME("hConv is NULL\n");
return 0;
}
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv != NULL)
{
if (!WDML_GetLocalConvInfo(pConv, &ci, id))
ret = 0;
}
else
{
if ((ULONG_PTR)hConv & 1)
{
pConv = WDML_GetConv((HCONV)((ULONG_PTR)hConv & ~1), FALSE);
if (pConv != NULL)
FIXME("Request on remote conversation information is not implemented yet\n");
}
ret = 0;
}
LeaveCriticalSection(&WDML_CritSect);
if (ret != 0)
memcpy(lpConvInfo, &ci, min((size_t)lpConvInfo->cb, sizeof(ci)));
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
*
* ================================================================ */
struct tagWDML_BroadcastPmt
{
LPCWSTR clsName;
UINT uMsg;
WPARAM wParam;
LPARAM lParam;
};
/******************************************************************
* WDML_BroadcastEnumProc
*
*
*/
static BOOL CALLBACK WDML_BroadcastEnumProc(HWND hWnd, LPARAM lParam)
{
struct tagWDML_BroadcastPmt* s = (struct tagWDML_BroadcastPmt*)lParam;
WCHAR buffer[128];
if (GetClassNameW(hWnd, buffer, 128) > 0 &&
lstrcmpiW(buffer, s->clsName) == 0)
{
PostMessageW(hWnd, s->uMsg, s->wParam, s->lParam);
}
return TRUE;
}
/******************************************************************
* WDML_BroadcastDDEWindows
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -