📄 ddeclient.c
字号:
{
WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_REQUEST transaction\n");
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) return NULL;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, wFmt, hszItem);
if (!pXAct)
{
GlobalDeleteAtom(atom);
return NULL;
}
pXAct->lParam = PackDDElParam(WM_DDE_REQUEST, wFmt, atom);
return pXAct;
}
/******************************************************************
* WDML_HandleRequestReply
*
*
*/
static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
{
DDEACK ddeAck;
WINE_DDEHEAD wdh;
UINT_PTR uiLo, uiHi;
HSZ hsz;
if ((HWND)msg->wParam != pConv->hwndServer)
return WDML_QS_PASS;
switch (msg->message)
{
case WM_DDE_ACK:
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam);
GlobalDeleteAtom(uiHi);
if (ack) *ack = uiLo;
WDML_ExtractAck(uiLo, &ddeAck);
pXAct->hDdeData = 0;
if (ddeAck.fAck)
ERR("Positive answer should appear in NACK for a request, assuming negative\n");
TRACE("Negative answer...\n");
break;
case WM_DDE_DATA:
UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
TRACE("Got the result (%08x)\n", uiLo);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
return WDML_QS_PASS;
pXAct->hDdeData = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
if (wdh.fRelease)
{
GlobalFree((HGLOBAL)uiLo);
}
if (wdh.fAckReq)
{
WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA);
}
else
{
GlobalDeleteAtom(uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam);
}
break;
default:
FreeDDElParam(msg->message, msg->lParam);
return WDML_QS_PASS;
}
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_BuildExecuteCommand
*
* Creates a DDE block suitable for sending in WM_DDE_COMMAND
* It also takes care of string conversion between the two window procedures
*/
static HGLOBAL WDML_BuildExecuteCommand(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
{
HGLOBAL hMem;
BOOL clientUnicode, serverUnicode;
DWORD memSize;
clientUnicode = pConv->instance->unicode;
TRACE("client %p uses unicode = %d\n", pConv->hwndClient, clientUnicode);
/* FIXME: how exactly Windows determines what to use for the server side? */
serverUnicode = IsWindowUnicode(pConv->hwndServer) && IsWindowUnicode(pConv->hwndClient);
TRACE("server %p uses unicode = %d\n", pConv->hwndServer, serverUnicode);
if (clientUnicode == serverUnicode)
{
memSize = cbData;
}
else
{
if (clientUnicode)
{
memSize = WideCharToMultiByte( CP_ACP, 0, pData, cbData, NULL, 0, NULL, NULL);
}
else
{
memSize = MultiByteToWideChar( CP_ACP, 0, pData, cbData, NULL, 0) * sizeof(WCHAR);
}
}
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, memSize);
if (hMem)
{
LPSTR pDst;
pDst = GlobalLock(hMem);
if (pDst)
{
if (clientUnicode == serverUnicode)
{
memcpy(pDst, pData, cbData);
}
else
{
if (clientUnicode)
{
WideCharToMultiByte( CP_ACP, 0, pData, cbData, pDst, memSize, NULL, NULL);
}
else
{
MultiByteToWideChar( CP_ACP, 0, pData, cbData, (LPWSTR)pDst, memSize/sizeof(WCHAR));
}
}
GlobalUnlock(hMem);
}
else
{
GlobalFree(hMem);
hMem = 0;
}
}
return hMem;
}
/******************************************************************
* WDML_ClientQueueExecute
*
*
*/
static WDML_XACT* WDML_ClientQueueExecute(WDML_CONV* pConv, LPCVOID pData, DWORD cbData)
{
WDML_XACT* pXAct;
TRACE("XTYP_EXECUTE transaction\n");
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0);
if (!pXAct)
return NULL;
if (cbData == (DWORD)-1)
{
HDDEDATA hDdeData = (HDDEDATA)pData;
pData = DdeAccessData(hDdeData, &cbData);
if (pData)
{
pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
DdeUnaccessData(hDdeData);
}
}
else
{
pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData);
}
pXAct->lParam = (LPARAM)pXAct->hMem;
return pXAct;
}
/******************************************************************
* WDML_HandleExecuteReply
*
*
*/
static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
{
DDEACK ddeAck;
UINT_PTR uiLo, uiHi;
if (msg->message != WM_DDE_ACK || (HWND)msg->wParam != pConv->hwndServer)
{
return WDML_QS_PASS;
}
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
FreeDDElParam(WM_DDE_ACK, msg->lParam);
if ((HANDLE)uiHi != pXAct->hMem)
{
return WDML_QS_PASS;
}
if (ack) *ack = uiLo;
WDML_ExtractAck(uiLo, &ddeAck);
pXAct->hDdeData = (HDDEDATA)(UINT_PTR)ddeAck.fAck;
TRACE("hDdeData = %p\n", pXAct->hDdeData);
pConv->instance->lastError = (pXAct->hDdeData != 0) ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED;
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_ClientQueuePoke
*
*
*/
static WDML_XACT* WDML_ClientQueuePoke(WDML_CONV* pConv, LPCVOID pData, DWORD cbData,
UINT wFmt, HSZ hszItem)
{
WDML_XACT* pXAct;
ATOM atom;
TRACE("XTYP_POKE transaction\n");
atom = WDML_MakeAtomFromHsz(hszItem);
if (!atom) return NULL;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE, wFmt, hszItem);
if (!pXAct)
{
GlobalDeleteAtom(atom);
return NULL;
}
if (cbData == (DWORD)-1)
{
pXAct->hMem = (HDDEDATA)pData;
}
else
{
DDEPOKE* ddePoke;
pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEPOKE) + cbData);
ddePoke = GlobalLock(pXAct->hMem);
if (ddePoke)
{
memcpy(ddePoke->Value, pData, cbData);
ddePoke->fRelease = FALSE; /* FIXME: app owned ? */
ddePoke->cfFormat = wFmt;
GlobalUnlock(pXAct->hMem);
}
}
pXAct->lParam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)pXAct->hMem, atom);
return pXAct;
}
/******************************************************************
* WDML_HandlePokeReply
*
*
*/
static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack)
{
UINT_PTR uiLo, uiHi;
HSZ hsz;
if (msg->message != WM_DDE_ACK && (HWND)msg->wParam != pConv->hwndServer)
{
return WDML_QS_PASS;
}
UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0)
{
return WDML_QS_PASS;
}
FreeDDElParam(WM_DDE_ACK, msg->lParam);
GlobalDeleteAtom(uiHi);
if (ack) *ack = uiLo;
GlobalFree(pXAct->hMem);
pXAct->hDdeData = (HDDEDATA)TRUE;
return TRUE;
}
/******************************************************************
* WDML_ClientQueueTerminate
*
* Creates and queue an WM_DDE_TERMINATE transaction
*/
static WDML_XACT* WDML_ClientQueueTerminate(WDML_CONV* pConv)
{
WDML_XACT* pXAct;
pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0);
if (!pXAct)
return NULL;
pXAct->lParam = 0;
pConv->wStatus &= ~ST_CONNECTED;
return pXAct;
}
/******************************************************************
* WDML_HandleTerminateReply
*
* handles the reply to a terminate request
*/
static WDML_QUEUE_STATE WDML_HandleTerminateReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct)
{
if (msg->message != WM_DDE_TERMINATE)
{
/* FIXME: should delete data passed here */
return WDML_QS_SWALLOWED;
}
if ((HWND)msg->wParam != pConv->hwndServer)
{
FIXME("hmmm shouldn't happen\n");
return WDML_QS_PASS;
}
if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
{
WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
}
WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_HandleReplyData
*
*
*/
static WDML_QUEUE_STATE WDML_HandleIncomingData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
{
UINT_PTR uiLo, uiHi;
HDDEDATA hDdeDataIn, hDdeDataOut;
WDML_LINK* pLink;
WINE_DDEHEAD wdh;
HSZ hsz;
TRACE("WM_DDE_DATA message received in the Client Proc!\n");
/* wParam -- sending window handle */
/* lParam -- hDdeData & item HSZ */
UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi);
hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi);
hDdeDataIn = WDML_Global2DataHandle((HGLOBAL)uiLo, &wdh);
/* billx:
* For hot link, data should be passed to its callback with
* XTYP_ADVDATA and callback should return the proper status.
*/
pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, hsz,
uiLo ? TRUE : FALSE, wdh.cfFormat);
if (!pLink)
{
WDML_DecHSZ(pConv->instance, hsz);
DdeFreeDataHandle(hDdeDataIn);
return WDML_QS_PASS;
}
if (hDdeDataIn != 0 && wdh.fAckReq)
{
WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA);
if (msg->lParam)
msg->lParam = 0;
}
else
{
GlobalDeleteAtom(uiHi);
}
hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv,
pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0);
if (hDdeDataOut != (HDDEDATA)DDE_FACK || wdh.fRelease)
{
if (uiLo) GlobalFree((HANDLE)uiLo);
}
DdeFreeDataHandle(hDdeDataIn);
WDML_DecHSZ(pConv->instance, hsz);
if (msg->lParam)
FreeDDElParam(WM_DDE_DATA, msg->lParam);
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_HandleIncomingTerminate
*
*
*/
static WDML_QUEUE_STATE WDML_HandleIncomingTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd)
{
if (pConv->hwndServer != (HWND)msg->wParam)
return WDML_QS_PASS;
pConv->wStatus |= ST_TERMINATED;
if (!pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)
{
WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv,
0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0);
}
if (pConv->wStatus & ST_CONNECTED)
{
/* don't care about result code (if server exists or not) */
PostMessageW(pConv->hwndServer, WM_DDE_TERMINATE, (WPARAM)pConv->hwndClient, 0L);
pConv->wStatus &= ~ST_CONNECTED;
}
/* have to keep connection around to allow reconnection */
return WDML_QS_HANDLED;
}
/******************************************************************
* WDML_HandleReply
*
* handles any incoming reply, and try to match to an already sent request
*/
static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd, DWORD *ack)
{
WDML_XACT* pXAct = pConv->transactions;
WDML_QUEUE_STATE qs;
if (pConv->transactions)
{
/* first check message against a pending transaction, if any */
switch (pXAct->ddeMsg)
{
case WM_DDE_ADVISE:
qs = WDML_HandleAdviseReply(pConv, msg, pXAct, ack);
break;
case WM_DDE_UNADVISE:
qs = WDML_HandleUnadviseReply(pConv, msg, pXAct, ack);
break;
case WM_DDE_EXECUTE:
qs = WDML_HandleExecuteReply(pConv, msg, pXAct, ack);
break;
case WM_DDE_REQUEST:
qs = WDML_HandleRequestReply(pConv, msg, pXAct, ack);
break;
case WM_DDE_POKE:
qs = WDML_HandlePokeReply(pConv, msg, pXAct, ack);
break;
case WM_DDE_TERMINATE:
qs = WDML_HandleTerminateReply(pConv, msg, pXAct);
break;
default:
qs = WDML_QS_ERROR;
FIXME("oooch\n");
}
}
else
{
qs = WDML_QS_PASS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -