📄 server.c
字号:
/* -*- tab-width: 8; c-basic-offset: 4 -*- *//* * DDEML library * * Copyright 1997 Alexandre Julliard * Copyright 1997 Len White * Copyright 1999 Keith Matthews * Copyright 2000 Corel * Copyright 2001 Eric Pouech * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <stdarg.h>#include <string.h>#include "windef.h"#include "winbase.h"#include "wingdi.h"#include "winuser.h"#include "winerror.h"#include "dde.h"#include "ddeml.h"#include "win.h"#include "wine/debug.h"#include "dde/dde_private.h"WINE_DEFAULT_DEBUG_CHANNEL(ddeml);static const char szServerNameClassA[] = "DdeServerNameAnsi";const char WDML_szServerConvClassA[] = "DdeServerConvAnsi";const WCHAR WDML_szServerConvClassW[] = {'D','d','e','S','e','r','v','e','r','C','o','n','v','U','n','i','c','o','d','e',0};static LRESULT CALLBACK WDML_ServerNameProc(HWND, UINT, WPARAM, LPARAM);static LRESULT CALLBACK WDML_ServerConvProc(HWND, UINT, WPARAM, LPARAM);/****************************************************************************** * DdePostAdvise [USER32.@] Send transaction to DDE callback function. * * PARAMS * idInst [I] Instance identifier * hszTopic [I] Handle to topic name string * hszItem [I] Handle to item name string * * RETURNS * Success: TRUE * Failure: FALSE */BOOL WINAPI DdePostAdvise(DWORD idInst, HSZ hszTopic, HSZ hszItem){ WDML_INSTANCE* pInstance = NULL; WDML_LINK* pLink = NULL; HDDEDATA hDdeData = 0; HGLOBAL hItemData = 0; WDML_CONV* pConv = NULL; ATOM atom = 0; UINT count; TRACE("(%ld,%p,%p)\n", idInst, hszTopic, hszItem); EnterCriticalSection(&WDML_CritSect); pInstance = WDML_GetInstance(idInst); if (pInstance == NULL || pInstance->links == NULL) { goto theError; } atom = WDML_MakeAtomFromHsz(hszItem); if (!atom) goto theError; /* first compute the number of links which will trigger a message */ count = 0; for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next) { if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0) { count++; } } if (count >= CADV_LATEACK) { FIXME("too high value for count\n"); count &= 0xFFFF; } for (pLink = pInstance->links[WDML_SERVER_SIDE]; pLink != NULL; pLink = pLink->next) { if (DdeCmpStringHandles(hszItem, pLink->hszItem) == 0) { hDdeData = WDML_InvokeCallback(pInstance, XTYP_ADVREQ, pLink->uFmt, pLink->hConv, hszTopic, hszItem, 0, --count, 0); if (hDdeData == (HDDEDATA)CBR_BLOCK) { /* MS doc is not consistent here */ FIXME("CBR_BLOCK returned for ADVREQ\n"); continue; } if (hDdeData) { if (pLink->transactionType & XTYPF_NODATA) { TRACE("no data\n"); hItemData = 0; } else { TRACE("with data\n"); hItemData = WDML_DataHandle2Global(hDdeData, FALSE, FALSE, FALSE, FALSE); } pConv = WDML_GetConv(pLink->hConv, TRUE); if (pConv == NULL) { if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData); goto theError; } if (!PostMessageA(pConv->hwndClient, WM_DDE_DATA, (WPARAM)pConv->hwndServer, PackDDElParam(WM_DDE_DATA, (UINT_PTR)hItemData, atom))) { ERR("post message failed\n"); pConv->wStatus &= ~ST_CONNECTED; if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData); GlobalFree(hItemData); goto theError; } if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData); } } } LeaveCriticalSection(&WDML_CritSect); return TRUE; theError: LeaveCriticalSection(&WDML_CritSect); if (atom) GlobalDeleteAtom(atom); return FALSE;}/****************************************************************************** * DdeNameService [USER32.@] {Un}registers service name of DDE server * * PARAMS * idInst [I] Instance identifier * hsz1 [I] Handle to service name string * hsz2 [I] Reserved * afCmd [I] Service name flags * * RETURNS * Success: Non-zero * Failure: 0 */HDDEDATA WINAPI DdeNameService(DWORD idInst, HSZ hsz1, HSZ hsz2, UINT afCmd){ WDML_SERVER* pServer; WDML_INSTANCE* pInstance; HDDEDATA hDdeData; HWND hwndServer; WNDCLASSEXA wndclass; hDdeData = NULL; TRACE("(%ld,%p,%p,%x)\n", idInst, hsz1, hsz2, afCmd); EnterCriticalSection(&WDML_CritSect); /* First check instance */ pInstance = WDML_GetInstance(idInst); if (pInstance == NULL) { TRACE("Instance not found as initialised\n"); /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */ goto theError; } if (hsz2 != 0L) { /* Illegal, reserved parameter */ pInstance->lastError = DMLERR_INVALIDPARAMETER; WARN("Reserved parameter no-zero !!\n"); goto theError; } if (hsz1 == 0 && !(afCmd & DNS_UNREGISTER)) { /* don't know if we should check this but it makes sense * why supply REGISTER or filter flags if de-registering all */ TRACE("General unregister unexpected flags\n"); pInstance->lastError = DMLERR_INVALIDPARAMETER; goto theError; } switch (afCmd & (DNS_REGISTER | DNS_UNREGISTER)) { case DNS_REGISTER: pServer = WDML_FindServer(pInstance, hsz1, 0); if (pServer) { ERR("Trying to register already registered service!\n"); pInstance->lastError = DMLERR_DLL_USAGE; goto theError; } TRACE("Adding service name\n"); WDML_IncHSZ(pInstance, hsz1); pServer = WDML_AddServer(pInstance, hsz1, 0); WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_REGISTER, pServer->atomService, pServer->atomServiceSpec); wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ServerNameProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szServerNameClassA; wndclass.hIconSm = 0; RegisterClassExA(&wndclass); LeaveCriticalSection(&WDML_CritSect); hwndServer = CreateWindowA(szServerNameClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0); EnterCriticalSection(&WDML_CritSect); SetWindowLongA(hwndServer, GWL_WDML_INSTANCE, (DWORD)pInstance); SetWindowLongA(hwndServer, GWL_WDML_SERVER, (DWORD)pServer); TRACE("Created nameServer=%p for instance=%08lx\n", hwndServer, idInst); pServer->hwndServer = hwndServer; break; case DNS_UNREGISTER: if (hsz1 == 0L) { /* General unregister situation * terminate all server side pending conversations */ while (pInstance->servers) WDML_RemoveServer(pInstance, pInstance->servers->hszService, 0); pInstance->servers = NULL; TRACE("General de-register - finished\n"); } else { WDML_RemoveServer(pInstance, hsz1, 0L); } break; } if (afCmd & (DNS_FILTERON | DNS_FILTEROFF)) { /* Set filter flags on to hold notifications of connection */ pServer = WDML_FindServer(pInstance, hsz1, 0); if (!pServer) { /* trying to filter where no service names !! */ pInstance->lastError = DMLERR_DLL_USAGE; goto theError; } else { pServer->filterOn = (afCmd & DNS_FILTERON) != 0; } } LeaveCriticalSection(&WDML_CritSect); return (HDDEDATA)TRUE; theError: LeaveCriticalSection(&WDML_CritSect); return FALSE;}/****************************************************************** * WDML_CreateServerConv * * */static WDML_CONV* WDML_CreateServerConv(WDML_INSTANCE* pInstance, HWND hwndClient, HWND hwndServerName, HSZ hszApp, HSZ hszTopic){ HWND hwndServerConv; WDML_CONV* pConv; if (pInstance->unicode) { WNDCLASSEXW wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ServerConvProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WDML_szServerConvClassW; wndclass.hIconSm = 0; RegisterClassExW(&wndclass); hwndServerConv = CreateWindowW(WDML_szServerConvClassW, 0, WS_CHILD, 0, 0, 0, 0, hwndServerName, 0, 0, 0); } else { WNDCLASSEXA wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WDML_ServerConvProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 2 * sizeof(DWORD); wndclass.hInstance = 0; wndclass.hIcon = 0; wndclass.hCursor = 0; wndclass.hbrBackground = 0; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = WDML_szServerConvClassA; wndclass.hIconSm = 0; RegisterClassExA(&wndclass); hwndServerConv = CreateWindowA(WDML_szServerConvClassA, 0, WS_CHILD, 0, 0, 0, 0, hwndServerName, 0, 0, 0); } TRACE("Created convServer=%p (nameServer=%p) for instance=%08lx\n", hwndServerConv, hwndServerName, pInstance->instanceID); pConv = WDML_AddConv(pInstance, WDML_SERVER_SIDE, hszApp, hszTopic, hwndClient, hwndServerConv); if (pConv) { SetWindowLongA(hwndServerConv, GWL_WDML_INSTANCE, (DWORD)pInstance); SetWindowLongA(hwndServerConv, GWL_WDML_CONVERSATION, (DWORD)pConv); /* this should be the only place using SendMessage for WM_DDE_ACK */ /* note: sent messages shall not use packing */ SendMessageA(hwndClient, WM_DDE_ACK, (WPARAM)hwndServerConv, MAKELPARAM(WDML_MakeAtomFromHsz(hszApp), WDML_MakeAtomFromHsz(hszTopic))); /* we assume we're connected since we've sent an answer... * I'm not sure what we can do... it doesn't look like the return value * of SendMessage is used... sigh... */ pConv->wStatus |= ST_CONNECTED; } else { DestroyWindow(hwndServerConv); } return pConv;}/****************************************************************** * WDML_ServerNameProc * * */static LRESULT CALLBACK WDML_ServerNameProc(HWND hwndServer, UINT iMsg, WPARAM wParam, LPARAM lParam){ HWND hwndClient; HSZ hszApp, hszTop; HDDEDATA hDdeData = 0; WDML_INSTANCE* pInstance; UINT_PTR uiLo, uiHi; switch (iMsg) { case WM_DDE_INITIATE: /* wParam -- sending window handle LOWORD(lParam) -- application atom HIWORD(lParam) -- topic atom */ TRACE("WM_DDE_INITIATE message received!\n"); hwndClient = (HWND)wParam; pInstance = WDML_GetInstanceFromWnd(hwndServer); TRACE("idInst=%ld, threadID=0x%lx\n", pInstance->instanceID, GetCurrentThreadId()); if (!pInstance) return 0; /* don't free DDEParams, since this is a broadcast */ UnpackDDElParam(WM_DDE_INITIATE, lParam, &uiLo, &uiHi); hszApp = WDML_MakeHszFromAtom(pInstance, uiLo); hszTop = WDML_MakeHszFromAtom(pInstance, uiHi); if (!(pInstance->CBFflags & CBF_FAIL_CONNECTIONS)) { BOOL self = FALSE; CONVCONTEXT cc; CONVCONTEXT* pcc = NULL; WDML_CONV* pConv; char buf[256]; if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) && WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer)) { self = TRUE; } /* FIXME: so far, we don't grab distant convcontext, so only check if remote is * handled under DDEML, and if so build a default context */ if ((GetClassNameA(hwndClient, buf, sizeof(buf)) && strcmp(buf, WDML_szClientConvClassA) == 0) || (GetClassNameW(hwndClient, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) && lstrcmpW((LPWSTR)buf, WDML_szClientConvClassW) == 0)) { pcc = &cc; memset(pcc, 0, sizeof(*pcc)); pcc->cb = sizeof(*pcc); pcc->iCodePage = IsWindowUnicode(hwndClient) ? CP_WINUNICODE : CP_WINANSI; } if ((pInstance->CBFflags & CBF_FAIL_SELFCONNECTIONS) && self) { TRACE("Don't do self connection as requested\n"); } else if (hszApp && hszTop) { WDML_SERVER* pServer = (WDML_SERVER*)GetWindowLongA(hwndServer, GWL_WDML_SERVER); /* check filters for name service */ if (!pServer->filterOn || DdeCmpStringHandles(pServer->hszService, hszApp) == 0) { /* pass on to the callback */ hDdeData = WDML_InvokeCallback(pInstance, XTYP_CONNECT, 0, 0, hszTop, hszApp, 0, (DWORD)pcc, self); if ((UINT)hDdeData) { pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer, hszApp, hszTop); if (pConv) { if (pcc) pConv->wStatus |= ST_ISLOCAL; WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv, hszTop, hszApp, 0, (DWORD)pcc, self); } } } } else if (pInstance->servers) { /* pass on to the callback */ hDdeData = WDML_InvokeCallback(pInstance, XTYP_WILDCONNECT, 0, 0, hszTop, hszApp, 0, (DWORD)pcc, self); if (hDdeData == (HDDEDATA)CBR_BLOCK) { /* MS doc is not consistent here */ FIXME("CBR_BLOCK returned for WILDCONNECT\n"); } else if ((UINT)hDdeData != 0) { HSZPAIR* hszp; hszp = (HSZPAIR*)DdeAccessData(hDdeData, NULL); if (hszp) { int i; for (i = 0; hszp[i].hszSvc && hszp[i].hszTopic; i++) { pConv = WDML_CreateServerConv(pInstance, hwndClient, hwndServer, hszp[i].hszSvc, hszp[i].hszTopic); if (pConv) { if (pcc) pConv->wStatus |= ST_ISLOCAL; WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv, hszp[i].hszTopic, hszp[i].hszSvc, 0, (DWORD)pcc, self); } } DdeUnaccessData(hDdeData); } if (!WDML_IsAppOwned(hDdeData)) DdeFreeDataHandle(hDdeData); } } } return 0; case WM_DDE_REQUEST: FIXME("WM_DDE_REQUEST message received!\n"); return 0; case WM_DDE_ADVISE: FIXME("WM_DDE_ADVISE message received!\n"); return 0; case WM_DDE_UNADVISE: FIXME("WM_DDE_UNADVISE message received!\n"); return 0; case WM_DDE_EXECUTE: FIXME("WM_DDE_EXECUTE message received!\n"); return 0; case WM_DDE_POKE: FIXME("WM_DDE_POKE message received!\n"); return 0; case WM_DDE_TERMINATE: FIXME("WM_DDE_TERMINATE message received!\n"); return 0; } return DefWindowProcA(hwndServer, iMsg, wParam, lParam);}/******************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -