⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ddeclient.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 3 页
字号:
    }

    /* 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 + -