📄 ddeclient.c
字号:
}
/* now check the results */
switch (qs)
{
case WDML_QS_ERROR:
case WDML_QS_SWALLOWED:
*hdd = 0;
break;
case WDML_QS_HANDLED:
/* ok, we have resolved a pending transaction
* notify callback if asynchronous, and remove it in any case
*/
WDML_UnQueueTransaction(pConv, pXAct);
if (pXAct->dwTimeout == TIMEOUT_ASYNC && pXAct->ddeMsg != WM_DDE_TERMINATE)
{
WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt,
(HCONV)pConv, pConv->hszTopic, pXAct->hszItem,
pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */);
qs = WDML_QS_PASS;
}
else
{
*hdd = pXAct->hDdeData;
}
WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
break;
case WDML_QS_PASS:
/* no pending transaction found, try a warm/hot link or a termination request */
switch (msg->message)
{
case WM_DDE_DATA:
qs = WDML_HandleIncomingData(pConv, msg, hdd);
break;
case WM_DDE_TERMINATE:
qs = WDML_HandleIncomingTerminate(pConv, msg, hdd);
break;
}
break;
case WDML_QS_BLOCK:
FIXME("shouldn't be used on client side\n");
break;
}
return qs;
}
/******************************************************************
* WDML_SyncWaitTransactionReply
*
* waits until an answer for a sent request is received
* time out is also handled. only used for synchronous transactions
*/
static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, WDML_XACT* pXAct, DWORD *ack)
{
DWORD dwTime;
DWORD err;
WDML_CONV* pConv;
TRACE("Starting wait for a timeout of %ld ms\n", dwTimeout);
/* FIXME: time 32 bit wrap around */
dwTimeout += GetCurrentTime();
while ((dwTime = GetCurrentTime()) < dwTimeout)
{
/* we cannot be in the crit sect all the time because when client and server run in a
* single process they need to share the access to the internal data
*/
if (MsgWaitForMultipleObjects(0, NULL, FALSE,
dwTimeout - dwTime, QS_POSTMESSAGE) == WAIT_OBJECT_0)
{
MSG msg;
while (PeekMessageW(&msg, 0, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE))
{
WDML_CONV *pConv;
HDDEDATA hdd;
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv == NULL)
{
LeaveCriticalSection(&WDML_CritSect);
/* conversation no longer available... return failure */
return 0;
}
if (msg.hwnd == pConv->hwndClient)
{
/* check that either pXAct has been processed or no more xActions are pending */
BOOL ret = (pConv->transactions == pXAct);
if (WDML_HandleReply(pConv, &msg, &hdd, ack) == WDML_QS_HANDLED)
{
TRACE("WDML_HandleReply returned WDML_QS_HANDLED\n");
ret = TRUE;
}
else
ret = (pConv->transactions == NULL || ret);
if (ret)
{
pConv->instance->lastError = hdd ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED;
LeaveCriticalSection(&WDML_CritSect);
return hdd;
}
}
else
{
LeaveCriticalSection(&WDML_CritSect);
DispatchMessageW(&msg);
}
}
}
}
TRACE("Timeout !!\n");
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, FALSE);
if (pConv != NULL)
{
if (pConv->transactions)
{
switch (pConv->transactions->ddeMsg)
{
case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break;
case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break;
case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break;
case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break;
case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break;
default: err = DMLERR_INVALIDPARAMETER; break;
}
pConv->instance->lastError = err;
}
}
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
/*****************************************************************
* DdeClientTransaction (USER32.@)
*/
HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt,
UINT wType, DWORD dwTimeout, LPDWORD pdwResult)
{
WDML_CONV* pConv;
WDML_XACT* pXAct;
HDDEDATA hDdeData = 0;
TRACE("(%p,%ld,%p,%p,%x,%x,%ld,%p)\n",
pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult);
if (hConv == 0)
{
WARN("Invalid conversation handle NULL\n");
return 0;
}
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, TRUE);
if (pConv == NULL)
{
/* cannot set error... cannot get back to DDE instance */
goto theError;
}
switch (wType)
{
case XTYP_EXECUTE:
/* Windows simply ignores hszItem and wFmt in this case */
pXAct = WDML_ClientQueueExecute(pConv, pData, cbData);
break;
case XTYP_POKE:
pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem);
break;
case XTYP_ADVSTART|XTYPF_NODATA:
case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ:
case XTYP_ADVSTART:
case XTYP_ADVSTART|XTYPF_ACKREQ:
if (pData)
{
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem);
break;
case XTYP_ADVSTOP:
if (pData)
{
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem);
break;
case XTYP_REQUEST:
if (pData)
{
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem);
break;
default:
FIXME("Unknown transation\n");
/* unknown transaction type */
pConv->instance->lastError = DMLERR_INVALIDPARAMETER;
goto theError;
}
if (pXAct == NULL)
{
pConv->instance->lastError = DMLERR_MEMORY_ERROR;
goto theError;
}
WDML_QueueTransaction(pConv, pXAct);
if (!PostMessageW(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam))
{
WARN("Failed posting message %x to %p (error=0x%lx)\n",
pXAct->ddeMsg, pConv->hwndServer, GetLastError());
pConv->wStatus &= ~ST_CONNECTED;
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
goto theError;
}
pXAct->dwTimeout = dwTimeout;
/* FIXME: should set the app bits on *pdwResult */
if (dwTimeout == TIMEOUT_ASYNC)
{
if (pdwResult)
{
*pdwResult = MAKELONG(0, pXAct->xActID);
}
hDdeData = (HDDEDATA)1;
}
else
{
DWORD count, i;
count = WDML_CritSect.RecursionCount;
for (i = 0; i < count; i++)
LeaveCriticalSection(&WDML_CritSect);
hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct, pdwResult);
for (i = 0; i < count; i++)
EnterCriticalSection(&WDML_CritSect);
}
LeaveCriticalSection(&WDML_CritSect);
return hDdeData;
theError:
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
/*****************************************************************
* DdeAbandonTransaction (USER32.@)
*/
BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction)
{
WDML_INSTANCE* pInstance;
WDML_CONV* pConv;
WDML_XACT* pXAct;
TRACE("(%08lx,%p,%08lx);\n", idInst, hConv, idTransaction);
EnterCriticalSection(&WDML_CritSect);
if ((pInstance = WDML_GetInstance(idInst)))
{
if (hConv)
{
if ((pConv = WDML_GetConv(hConv, TRUE)) && pConv->instance == pInstance)
{
for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next)
{
if (pXAct->dwTimeout == TIMEOUT_ASYNC &&
(idTransaction == 0 || pXAct->xActID == idTransaction))
{
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pInstance, pXAct, TRUE);
}
}
}
}
else
{
for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv; pConv = pConv->next)
{
if (!(pConv->wStatus & ST_CONNECTED)) continue;
for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next)
{
if (pXAct->dwTimeout == TIMEOUT_ASYNC)
{
WDML_UnQueueTransaction(pConv, pXAct);
WDML_FreeTransaction(pInstance, pXAct, TRUE);
}
}
}
}
}
LeaveCriticalSection(&WDML_CritSect);
return TRUE;
}
/******************************************************************
* WDML_ClientProc
*
* Window Proc created on client side for each conversation
*/
static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
UINT uiLo, uiHi;
WDML_CONV* pConv = NULL;
HSZ hszSrv, hszTpc;
TRACE("%p %04x %08x %08lx\n", hwnd, iMsg, wParam , lParam);
if (iMsg == WM_DDE_ACK &&
/* in the initial WM_INITIATE sendmessage */
((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1))
{
/* In response to WM_DDE_INITIATE, save server window */
char buf[256];
WDML_INSTANCE* pInstance;
/* note: sent messages do not need packing */
uiLo = LOWORD(lParam);
uiHi = HIWORD(lParam);
/* FIXME: convlist should be handled here */
if (pConv)
{
/* we already have started the conv with a server, drop other replies */
GlobalDeleteAtom(uiLo);
GlobalDeleteAtom(uiHi);
PostMessageW((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0);
return 0;
}
pInstance = WDML_GetInstanceFromWnd(hwnd);
hszSrv = WDML_MakeHszFromAtom(pInstance, uiLo);
hszTpc = WDML_MakeHszFromAtom(pInstance, uiHi);
pConv = WDML_AddConv(pInstance, WDML_CLIENT_SIDE, hszSrv, hszTpc, hwnd, (HWND)wParam);
SetWindowLongPtrW(hwnd, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv);
pConv->wStatus |= ST_CONNECTED;
pConv->wConvst = XST_INIT1;
/* check if server is handled by DDEML */
if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) &&
lstrcmpiA(buf, WDML_szServerConvClassA) == 0) ||
(GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) &&
lstrcmpiW((LPWSTR)buf, WDML_szServerConvClassW) == 0))
{
pConv->wStatus |= ST_ISLOCAL;
}
WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_CONNECT_CONFIRM, (WPARAM)hwnd, wParam);
GlobalDeleteAtom(uiLo);
GlobalDeleteAtom(uiHi);
/* accept conversation */
return 1;
}
if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST)
{
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConvFromWnd(hwnd);
if (pConv)
{
MSG msg;
HDDEDATA hdd;
msg.hwnd = hwnd;
msg.message = iMsg;
msg.wParam = wParam;
msg.lParam = lParam;
WDML_HandleReply(pConv, &msg, &hdd, NULL);
}
LeaveCriticalSection(&WDML_CritSect);
return 0;
}
return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, iMsg, wParam, lParam) :
DefWindowProcA(hwnd, iMsg, wParam, lParam);
}
/*****************************************************************
* DdeDisconnect (USER32.@)
*/
BOOL WINAPI DdeDisconnect(HCONV hConv)
{
WDML_CONV* pConv = NULL;
WDML_XACT* pXAct;
DWORD count, i;
BOOL ret = FALSE;
TRACE("(%p)\n", hConv);
if (hConv == 0)
{
WARN("DdeDisconnect(): hConv = 0\n");
return FALSE;
}
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, TRUE);
if (pConv != NULL)
{
if (pConv->wStatus & ST_CLIENT)
{
/* FIXME: should abandon all pending transactions */
pXAct = WDML_ClientQueueTerminate(pConv);
if (pXAct != NULL)
{
count = WDML_CritSect.RecursionCount;
for (i = 0; i < count; i++)
LeaveCriticalSection(&WDML_CritSect);
if (PostMessageW(pConv->hwndServer, pXAct->ddeMsg,
(WPARAM)pConv->hwndClient, pXAct->lParam))
WDML_SyncWaitTransactionReply(hConv, 10000, pXAct, NULL);
for (i = 0; i < count; i++)
EnterCriticalSection(&WDML_CritSect);
ret = TRUE;
WDML_FreeTransaction(pConv->instance, pXAct, TRUE);
/* still have to destroy data assosiated with conversation */
WDML_RemoveConv(pConv, WDML_CLIENT_SIDE);
}
else
{
FIXME("Not implemented yet for a server side conversation\n");
}
}
}
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
/*****************************************************************
* DdeImpersonateClient (USER32.@)
*/
BOOL WINAPI DdeImpersonateClient(HCONV hConv)
{
WDML_CONV* pConv;
BOOL ret = FALSE;
TRACE("(%p)\n", hConv);
EnterCriticalSection(&WDML_CritSect);
pConv = WDML_GetConv(hConv, TRUE);
if (pConv)
{
ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer);
}
LeaveCriticalSection(&WDML_CritSect);
return ret;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -