Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendde.c
Go to the documentation of this file.
00001 /* 00002 * DDEML library 00003 * 00004 * Copyright 1997 Alexandre Julliard 00005 * Copyright 1997 Len White 00006 * Copyright 1999 Keith Matthews 00007 * Copyright 2000 Corel 00008 * Copyright 2001 Eric Pouech 00009 * Copyright 2003, 2004, 2005 Dmitry Timoshkov 00010 * 00011 * This library is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU Lesser General Public 00013 * License as published by the Free Software Foundation; either 00014 * version 2.1 of the License, or (at your option) any later version. 00015 * 00016 * This library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with this library; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00024 */ 00025 00026 #include <user32.h> 00027 #include "dde_private.h" 00028 #include "wine/unicode.h" 00029 #include "wine/debug.h" 00030 00031 WINE_DEFAULT_DEBUG_CHANNEL(ddeml); 00032 00033 /* convert between ATOM and HSZ avoiding compiler warnings */ 00034 #define ATOM2HSZ(atom) ((HSZ) (ULONG_PTR)(atom)) 00035 #define HSZ2ATOM(hsz) ((ATOM) (ULONG_PTR)(hsz)) 00036 00037 static WDML_INSTANCE* WDML_InstanceList = NULL; 00038 static LONG WDML_MaxInstanceID = 0; /* OK for present, have to worry about wrap-around later */ 00039 const WCHAR WDML_szEventClass[] = {'D','d','e','E','v','e','n','t','C','l','a','s','s',0}; 00040 00041 /* protection for instance list */ 00042 CRITICAL_SECTION WDML_CritSect; 00043 CRITICAL_SECTION_DEBUG critsect_debug = 00044 { 00045 0, 0, &WDML_CritSect, 00046 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 00047 0, 0, { (DWORD_PTR)(__FILE__ ": WDML_CritSect") } 00048 }; 00049 CRITICAL_SECTION WDML_CritSect = { &critsect_debug, -1, 0, 0, 0, 0 }; 00050 00051 /* ================================================================ 00052 * 00053 * Pure DDE (non DDEML) management 00054 * 00055 * ================================================================ */ 00056 00057 00058 /***************************************************************** 00059 * PackDDElParam (USER32.@) 00060 * 00061 * RETURNS 00062 * the packed lParam 00063 */ 00064 LPARAM WINAPI PackDDElParam(UINT msg, UINT_PTR uiLo, UINT_PTR uiHi) 00065 { 00066 HGLOBAL hMem; 00067 UINT_PTR *params; 00068 00069 switch (msg) 00070 { 00071 case WM_DDE_ACK: 00072 case WM_DDE_ADVISE: 00073 case WM_DDE_DATA: 00074 case WM_DDE_POKE: 00075 if (!(hMem = GlobalAlloc(GMEM_DDESHARE, sizeof(UINT_PTR) * 2))) 00076 { 00077 ERR("GlobalAlloc failed\n"); 00078 return 0; 00079 } 00080 if (!(params = GlobalLock(hMem))) 00081 { 00082 ERR("GlobalLock failed (%p)\n", hMem); 00083 return 0; 00084 } 00085 params[0] = uiLo; 00086 params[1] = uiHi; 00087 GlobalUnlock(hMem); 00088 return (LPARAM)hMem; 00089 00090 case WM_DDE_EXECUTE: 00091 return uiHi; 00092 00093 default: 00094 return MAKELPARAM(uiLo, uiHi); 00095 } 00096 } 00097 00098 00099 /***************************************************************** 00100 * UnpackDDElParam (USER32.@) 00101 * 00102 * RETURNS 00103 * success: nonzero 00104 * failure: zero 00105 */ 00106 BOOL WINAPI UnpackDDElParam(UINT msg, LPARAM lParam, 00107 PUINT_PTR uiLo, PUINT_PTR uiHi) 00108 { 00109 UINT_PTR *params; 00110 00111 switch (msg) 00112 { 00113 case WM_DDE_ACK: 00114 case WM_DDE_ADVISE: 00115 case WM_DDE_DATA: 00116 case WM_DDE_POKE: 00117 if (!lParam || !(params = GlobalLock((HGLOBAL)lParam))) 00118 { 00119 if (uiLo) *uiLo = 0; 00120 if (uiHi) *uiHi = 0; 00121 return FALSE; 00122 } 00123 if (uiLo) *uiLo = params[0]; 00124 if (uiHi) *uiHi = params[1]; 00125 GlobalUnlock( (HGLOBAL)lParam ); 00126 return TRUE; 00127 00128 case WM_DDE_EXECUTE: 00129 if (uiLo) *uiLo = 0; 00130 if (uiHi) *uiHi = lParam; 00131 return TRUE; 00132 00133 default: 00134 if (uiLo) *uiLo = LOWORD(lParam); 00135 if (uiHi) *uiHi = HIWORD(lParam); 00136 return TRUE; 00137 } 00138 } 00139 00140 00141 /***************************************************************** 00142 * FreeDDElParam (USER32.@) 00143 * 00144 * RETURNS 00145 * success: nonzero 00146 * failure: zero 00147 */ 00148 BOOL WINAPI FreeDDElParam(UINT msg, LPARAM lParam) 00149 { 00150 switch (msg) 00151 { 00152 case WM_DDE_ACK: 00153 case WM_DDE_ADVISE: 00154 case WM_DDE_DATA: 00155 case WM_DDE_POKE: 00156 /* first check if it's a global handle */ 00157 if (!GlobalHandle( (LPVOID)lParam )) return TRUE; 00158 return !GlobalFree( (HGLOBAL)lParam ); 00159 00160 default: 00161 return TRUE; 00162 } 00163 } 00164 00165 00166 /***************************************************************** 00167 * ReuseDDElParam (USER32.@) 00168 * 00169 * RETURNS 00170 * the packed lParam 00171 */ 00172 LPARAM WINAPI ReuseDDElParam(LPARAM lParam, UINT msgIn, UINT msgOut, 00173 UINT_PTR uiLo, UINT_PTR uiHi) 00174 { 00175 UINT_PTR *params; 00176 00177 switch (msgIn) 00178 { 00179 case WM_DDE_ACK: 00180 case WM_DDE_ADVISE: 00181 case WM_DDE_DATA: 00182 case WM_DDE_POKE: 00183 switch(msgOut) 00184 { 00185 case WM_DDE_ACK: 00186 case WM_DDE_ADVISE: 00187 case WM_DDE_DATA: 00188 case WM_DDE_POKE: 00189 if (!lParam) return 0; 00190 if (!(params = GlobalLock( (HGLOBAL)lParam ))) 00191 { 00192 ERR("GlobalLock failed\n"); 00193 return 0; 00194 } 00195 params[0] = uiLo; 00196 params[1] = uiHi; 00197 TRACE("Reusing pack %08lx %08lx\n", uiLo, uiHi); 00198 GlobalUnlock( (HGLOBAL)lParam ); 00199 return lParam; 00200 00201 case WM_DDE_EXECUTE: 00202 FreeDDElParam( msgIn, lParam ); 00203 return uiHi; 00204 00205 default: 00206 FreeDDElParam( msgIn, lParam ); 00207 return MAKELPARAM(uiLo, uiHi); 00208 } 00209 00210 default: 00211 return PackDDElParam( msgOut, uiLo, uiHi ); 00212 } 00213 } 00214 00215 /***************************************************************** 00216 * ImpersonateDdeClientWindow (USER32.@) 00217 * 00218 * PARAMS 00219 * hWndClient [I] handle to DDE client window 00220 * hWndServer [I] handle to DDE server window 00221 */ 00222 BOOL WINAPI ImpersonateDdeClientWindow(HWND hWndClient, HWND hWndServer) 00223 { 00224 FIXME("(%p %p): stub\n", hWndClient, hWndServer); 00225 return FALSE; 00226 } 00227 00228 /***************************************************************** 00229 * DdeSetQualityOfService (USER32.@) 00230 */ 00231 00232 BOOL WINAPI DdeSetQualityOfService(HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew, 00233 PSECURITY_QUALITY_OF_SERVICE pqosPrev) 00234 { 00235 FIXME("(%p %p %p): stub\n", hwndClient, pqosNew, pqosPrev); 00236 return TRUE; 00237 } 00238 00239 /* ================================================================ 00240 * 00241 * Instance management 00242 * 00243 * ================================================================ */ 00244 00245 /****************************************************************************** 00246 * IncrementInstanceId 00247 * 00248 * generic routine to increment the max instance Id and allocate a new application instance 00249 */ 00250 static void WDML_IncrementInstanceId(WDML_INSTANCE* pInstance) 00251 { 00252 DWORD id = InterlockedIncrement(&WDML_MaxInstanceID); 00253 00254 pInstance->instanceID = id; 00255 TRACE("New instance id %d allocated\n", id); 00256 } 00257 00258 /****************************************************************** 00259 * WDML_EventProc 00260 * 00261 * 00262 */ 00263 static LRESULT CALLBACK WDML_EventProc(HWND hwndEvent, UINT uMsg, WPARAM wParam, LPARAM lParam) 00264 { 00265 WDML_INSTANCE* pInstance; 00266 HSZ hsz1, hsz2; 00267 00268 switch (uMsg) 00269 { 00270 case WM_WDML_REGISTER: 00271 pInstance = WDML_GetInstanceFromWnd(hwndEvent); 00272 /* try calling the Callback */ 00273 if (pInstance && !(pInstance->CBFflags & CBF_SKIP_REGISTRATIONS)) 00274 { 00275 hsz1 = WDML_MakeHszFromAtom(pInstance, wParam); 00276 hsz2 = WDML_MakeHszFromAtom(pInstance, lParam); 00277 WDML_InvokeCallback(pInstance, XTYP_REGISTER, 0, 0, hsz1, hsz2, 0, 0, 0); 00278 WDML_DecHSZ(pInstance, hsz1); 00279 WDML_DecHSZ(pInstance, hsz2); 00280 } 00281 break; 00282 00283 case WM_WDML_UNREGISTER: 00284 pInstance = WDML_GetInstanceFromWnd(hwndEvent); 00285 if (pInstance && !(pInstance->CBFflags & CBF_SKIP_UNREGISTRATIONS)) 00286 { 00287 hsz1 = WDML_MakeHszFromAtom(pInstance, wParam); 00288 hsz2 = WDML_MakeHszFromAtom(pInstance, lParam); 00289 WDML_InvokeCallback(pInstance, XTYP_UNREGISTER, 0, 0, hsz1, hsz2, 0, 0, 0); 00290 WDML_DecHSZ(pInstance, hsz1); 00291 WDML_DecHSZ(pInstance, hsz2); 00292 } 00293 break; 00294 00295 case WM_WDML_CONNECT_CONFIRM: 00296 pInstance = WDML_GetInstanceFromWnd(hwndEvent); 00297 if (pInstance && !(pInstance->CBFflags & CBF_SKIP_CONNECT_CONFIRMS)) 00298 { 00299 WDML_CONV* pConv; 00300 /* confirm connection... 00301 * lookup for this conv handle 00302 */ 00303 HWND client = (HWND)wParam; 00304 HWND server = (HWND)lParam; 00305 for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConv->next) 00306 { 00307 if (pConv->hwndClient == client && pConv->hwndServer == server) 00308 break; 00309 } 00310 if (pConv) 00311 { 00312 pConv->wStatus |= ST_ISLOCAL; 00313 00314 WDML_InvokeCallback(pInstance, XTYP_CONNECT_CONFIRM, 0, (HCONV)pConv, 00315 pConv->hszTopic, pConv->hszService, 0, 0, 00316 (pConv->wStatus & ST_ISSELF) ? 1 : 0); 00317 } 00318 } 00319 break; 00320 default: 00321 return DefWindowProcW(hwndEvent, uMsg, wParam, lParam); 00322 } 00323 return 0; 00324 } 00325 00326 /****************************************************************** 00327 * WDML_Initialize 00328 * 00329 * 00330 */ 00331 UINT WDML_Initialize(LPDWORD pidInst, PFNCALLBACK pfnCallback, 00332 DWORD afCmd, DWORD ulRes, BOOL bUnicode) 00333 { 00334 WDML_INSTANCE* pInstance; 00335 WDML_INSTANCE* reference_inst; 00336 UINT ret; 00337 WNDCLASSEXW wndclass; 00338 00339 TRACE("(%p,%p,0x%x,%d,0x%x)\n", 00340 pidInst, pfnCallback, afCmd, ulRes, bUnicode); 00341 00342 if (ulRes) 00343 { 00344 ERR("Reserved value not zero? What does this mean?\n"); 00345 /* trap this and no more until we know more */ 00346 return DMLERR_NO_ERROR; 00347 } 00348 00349 /* grab enough heap for one control struct - not really necessary for re-initialise 00350 * but allows us to use same validation routines */ 00351 pInstance = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_INSTANCE)); 00352 if (pInstance == NULL) 00353 { 00354 /* catastrophe !! warn user & abort */ 00355 ERR("Instance create failed - out of memory\n"); 00356 return DMLERR_SYS_ERROR; 00357 } 00358 pInstance->next = NULL; 00359 pInstance->monitor = (afCmd | APPCLASS_MONITOR); 00360 00361 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */ 00362 00363 pInstance->clientOnly = afCmd & APPCMD_CLIENTONLY; 00364 pInstance->instanceID = *pidInst; /* May need to add calling proc Id */ 00365 pInstance->threadID = GetCurrentThreadId(); 00366 pInstance->callback = *pfnCallback; 00367 pInstance->unicode = bUnicode; 00368 pInstance->nodeList = NULL; /* node will be added later */ 00369 pInstance->monitorFlags = afCmd & MF_MASK; 00370 pInstance->wStatus = 0; 00371 pInstance->lastError = DMLERR_NO_ERROR; 00372 pInstance->servers = NULL; 00373 pInstance->convs[0] = NULL; 00374 pInstance->convs[1] = NULL; 00375 pInstance->links[0] = NULL; 00376 pInstance->links[1] = NULL; 00377 00378 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */ 00379 00380 pInstance->CBFflags = afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK))); 00381 00382 if (!pInstance->clientOnly) 00383 { 00384 /* Check for other way of setting Client-only !! */ 00385 pInstance->clientOnly = 00386 (pInstance->CBFflags & CBF_FAIL_ALLSVRXACTIONS) == CBF_FAIL_ALLSVRXACTIONS; 00387 } 00388 00389 TRACE("instance created - checking validity\n"); 00390 00391 if (*pidInst == 0) 00392 { 00393 /* Initialisation of new Instance Identifier */ 00394 TRACE("new instance, callback %p flags %X\n",pfnCallback,afCmd); 00395 00396 EnterCriticalSection(&WDML_CritSect); 00397 00398 if (WDML_InstanceList == NULL) 00399 { 00400 /* can't be another instance in this case, assign to the base pointer */ 00401 WDML_InstanceList = pInstance; 00402 00403 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for 00404 * present 00405 * ------------------------------- NOTE NOTE NOTE -------------------------- 00406 * 00407 * the manual is not clear if this condition 00408 * applies to the first call to DdeInitialize from an application, or the 00409 * first call for a given callback !!! 00410 */ 00411 00412 pInstance->CBFflags = pInstance->CBFflags|APPCMD_FILTERINITS; 00413 TRACE("First application instance detected OK\n"); 00414 /* allocate new instance ID */ 00415 WDML_IncrementInstanceId(pInstance); 00416 } 00417 else 00418 { 00419 /* really need to chain the new one in to the latest here, but after checking conditions 00420 * such as trying to start a conversation from an application trying to monitor */ 00421 reference_inst = WDML_InstanceList; 00422 TRACE("Subsequent application instance - starting checks\n"); 00423 while (reference_inst->next != NULL) 00424 { 00425 /* 00426 * This set of tests will work if application uses same instance Id 00427 * at application level once allocated - which is what manual implies 00428 * should happen. If someone tries to be 00429 * clever (lazy ?) it will fail to pick up that later calls are for 00430 * the same application - should we trust them ? 00431 */ 00432 if (pInstance->instanceID == reference_inst->instanceID) 00433 { 00434 /* Check 1 - must be same Client-only state */ 00435 00436 if (pInstance->clientOnly != reference_inst->clientOnly) 00437 { 00438 ret = DMLERR_DLL_USAGE; 00439 goto theError; 00440 } 00441 00442 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */ 00443 00444 if (pInstance->monitor != reference_inst->monitor) 00445 { 00446 ret = DMLERR_INVALIDPARAMETER; 00447 goto theError; 00448 } 00449 00450 /* Check 3 - must supply different callback address */ 00451 00452 if (pInstance->callback == reference_inst->callback) 00453 { 00454 ret = DMLERR_DLL_USAGE; 00455 goto theError; 00456 } 00457 } 00458 reference_inst = reference_inst->next; 00459 } 00460 /* All cleared, add to chain */ 00461 00462 TRACE("Application Instance checks finished\n"); 00463 WDML_IncrementInstanceId(pInstance); 00464 reference_inst->next = pInstance; 00465 } 00466 LeaveCriticalSection(&WDML_CritSect); 00467 00468 *pidInst = pInstance->instanceID; 00469 00470 /* for deadlock issues, windows must always be created when outside the critical section */ 00471 wndclass.cbSize = sizeof(wndclass); 00472 wndclass.style = 0; 00473 wndclass.lpfnWndProc = WDML_EventProc; 00474 wndclass.cbClsExtra = 0; 00475 wndclass.cbWndExtra = sizeof(ULONG_PTR); 00476 wndclass.hInstance = 0; 00477 wndclass.hIcon = 0; 00478 wndclass.hCursor = 0; 00479 wndclass.hbrBackground = 0; 00480 wndclass.lpszMenuName = NULL; 00481 wndclass.lpszClassName = WDML_szEventClass; 00482 wndclass.hIconSm = 0; 00483 00484 RegisterClassExW(&wndclass); 00485 00486 pInstance->hwndEvent = CreateWindowW(WDML_szEventClass, NULL, 00487 WS_POPUP, 0, 0, 0, 0, 00488 0, 0, 0, 0); 00489 00490 SetWindowLongPtrW(pInstance->hwndEvent, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance); 00491 00492 TRACE("New application instance processing finished OK\n"); 00493 } 00494 else 00495 { 00496 /* Reinitialisation situation --- FIX */ 00497 TRACE("reinitialisation of (%p,%p,0x%x,%d): stub\n", pidInst, pfnCallback, afCmd, ulRes); 00498 00499 EnterCriticalSection(&WDML_CritSect); 00500 00501 if (WDML_InstanceList == NULL) 00502 { 00503 ret = DMLERR_INVALIDPARAMETER; 00504 goto theError; 00505 } 00506 /* can't reinitialise if we have initialised nothing !! */ 00507 reference_inst = WDML_InstanceList; 00508 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */ 00509 /* 00510 * MS allows initialisation without specifying a callback, should we allow addition of the 00511 * callback by a later call to initialise ? - if so this lot will have to change 00512 */ 00513 while (reference_inst->next != NULL) 00514 { 00515 if (*pidInst == reference_inst->instanceID && pfnCallback == reference_inst->callback) 00516 { 00517 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */ 00518 00519 if (reference_inst->clientOnly) 00520 { 00521 if ((reference_inst->CBFflags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS) 00522 { 00523 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */ 00524 00525 if (!(afCmd & APPCMD_CLIENTONLY)) 00526 { 00527 ret = DMLERR_INVALIDPARAMETER; 00528 goto theError; 00529 } 00530 } 00531 } 00532 /* Check 2 - cannot change monitor modes */ 00533 00534 if (pInstance->monitor != reference_inst->monitor) 00535 { 00536 ret = DMLERR_INVALIDPARAMETER; 00537 goto theError; 00538 } 00539 00540 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */ 00541 00542 if ((afCmd&APPCMD_CLIENTONLY) && !reference_inst->clientOnly) 00543 { 00544 ret = DMLERR_INVALIDPARAMETER; 00545 goto theError; 00546 } 00547 break; 00548 } 00549 reference_inst = reference_inst->next; 00550 } 00551 if (reference_inst->next == NULL) 00552 { 00553 ret = DMLERR_INVALIDPARAMETER; 00554 goto theError; 00555 } 00556 /* All checked - change relevant flags */ 00557 00558 reference_inst->CBFflags = pInstance->CBFflags; 00559 reference_inst->clientOnly = pInstance->clientOnly; 00560 reference_inst->monitorFlags = pInstance->monitorFlags; 00561 00562 HeapFree(GetProcessHeap(), 0, pInstance); /* finished - release heap space used as work store */ 00563 00564 LeaveCriticalSection(&WDML_CritSect); 00565 } 00566 00567 return DMLERR_NO_ERROR; 00568 theError: 00569 HeapFree(GetProcessHeap(), 0, pInstance); 00570 LeaveCriticalSection(&WDML_CritSect); 00571 return ret; 00572 } 00573 00574 /****************************************************************************** 00575 * DdeInitializeA (USER32.@) 00576 * 00577 * See DdeInitializeW. 00578 */ 00579 UINT WINAPI DdeInitializeA(LPDWORD pidInst, PFNCALLBACK pfnCallback, 00580 DWORD afCmd, DWORD ulRes) 00581 { 00582 return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, FALSE); 00583 } 00584 00585 /****************************************************************************** 00586 * DdeInitializeW [USER32.@] 00587 * Registers an application with the DDEML 00588 * 00589 * PARAMS 00590 * pidInst [I] Pointer to instance identifier 00591 * pfnCallback [I] Pointer to callback function 00592 * afCmd [I] Set of command and filter flags 00593 * ulRes [I] Reserved 00594 * 00595 * RETURNS 00596 * Success: DMLERR_NO_ERROR 00597 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR 00598 */ 00599 UINT WINAPI DdeInitializeW(LPDWORD pidInst, PFNCALLBACK pfnCallback, 00600 DWORD afCmd, DWORD ulRes) 00601 { 00602 return WDML_Initialize(pidInst, pfnCallback, afCmd, ulRes, TRUE); 00603 } 00604 00605 /***************************************************************** 00606 * DdeUninitialize [USER32.@] Frees DDEML resources 00607 * 00608 * PARAMS 00609 * idInst [I] Instance identifier 00610 * 00611 * RETURNS 00612 * Success: TRUE 00613 * Failure: FALSE 00614 */ 00615 00616 BOOL WINAPI DdeUninitialize(DWORD idInst) 00617 { 00618 /* Stage one - check if we have a handle for this instance 00619 */ 00620 WDML_INSTANCE* pInstance; 00621 WDML_CONV* pConv; 00622 WDML_CONV* pConvNext; 00623 00624 TRACE("(%d)\n", idInst); 00625 00626 /* First check instance 00627 */ 00628 pInstance = WDML_GetInstance(idInst); 00629 if (pInstance == NULL) 00630 { 00631 /* 00632 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError 00633 */ 00634 return FALSE; 00635 } 00636 00637 /* first terminate all conversations client side 00638 * this shall close existing links... 00639 */ 00640 for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv != NULL; pConv = pConvNext) 00641 { 00642 pConvNext = pConv->next; 00643 DdeDisconnect((HCONV)pConv); 00644 } 00645 if (pInstance->convs[WDML_CLIENT_SIDE]) 00646 FIXME("still pending conversations\n"); 00647 00648 /* then unregister all known service names */ 00649 DdeNameService(idInst, 0, 0, DNS_UNREGISTER); 00650 00651 /* Free the nodes that were not freed by this instance 00652 * and remove the nodes from the list of HSZ nodes. 00653 */ 00654 WDML_FreeAllHSZ(pInstance); 00655 00656 DestroyWindow(pInstance->hwndEvent); 00657 00658 /* OK now delete the instance handle itself */ 00659 00660 if (WDML_InstanceList == pInstance) 00661 { 00662 /* special case - the first/only entry */ 00663 WDML_InstanceList = pInstance->next; 00664 } 00665 else 00666 { 00667 /* general case, remove entry */ 00668 WDML_INSTANCE* inst; 00669 00670 for (inst = WDML_InstanceList; inst->next != pInstance; inst = inst->next); 00671 inst->next = pInstance->next; 00672 } 00673 /* release the heap entry 00674 */ 00675 HeapFree(GetProcessHeap(), 0, pInstance); 00676 00677 return TRUE; 00678 } 00679 00680 /****************************************************************** 00681 * WDML_NotifyThreadExit 00682 * 00683 * 00684 */ 00685 void WDML_NotifyThreadDetach(void) 00686 { 00687 WDML_INSTANCE* pInstance; 00688 WDML_INSTANCE* next; 00689 DWORD tid = GetCurrentThreadId(); 00690 00691 EnterCriticalSection(&WDML_CritSect); 00692 for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = next) 00693 { 00694 next = pInstance->next; 00695 if (pInstance->threadID == tid) 00696 { 00697 LeaveCriticalSection(&WDML_CritSect); 00698 DdeUninitialize(pInstance->instanceID); 00699 EnterCriticalSection(&WDML_CritSect); 00700 } 00701 } 00702 LeaveCriticalSection(&WDML_CritSect); 00703 } 00704 00705 /****************************************************************** 00706 * WDML_InvokeCallback 00707 * 00708 * 00709 */ 00710 HDDEDATA WDML_InvokeCallback(WDML_INSTANCE* pInstance, UINT uType, UINT uFmt, HCONV hConv, 00711 HSZ hsz1, HSZ hsz2, HDDEDATA hdata, 00712 ULONG_PTR dwData1, ULONG_PTR dwData2) 00713 { 00714 HDDEDATA ret; 00715 00716 if (pInstance == NULL) 00717 return NULL; 00718 00719 TRACE("invoking CB[%p] (%x %x %p %p %p %p %lx %lx)\n", 00720 pInstance->callback, uType, uFmt, 00721 hConv, hsz1, hsz2, hdata, dwData1, dwData2); 00722 ret = pInstance->callback(uType, uFmt, hConv, hsz1, hsz2, hdata, dwData1, dwData2); 00723 TRACE("done => %p\n", ret); 00724 return ret; 00725 } 00726 00727 /***************************************************************************** 00728 * WDML_GetInstance 00729 * 00730 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY 00731 * for an instance Id, or NULL if the entry does not exist 00732 * 00733 */ 00734 WDML_INSTANCE* WDML_GetInstance(DWORD instId) 00735 { 00736 WDML_INSTANCE* pInstance; 00737 00738 EnterCriticalSection(&WDML_CritSect); 00739 00740 for (pInstance = WDML_InstanceList; pInstance != NULL; pInstance = pInstance->next) 00741 { 00742 if (pInstance->instanceID == instId) 00743 { 00744 if (GetCurrentThreadId() != pInstance->threadID) 00745 { 00746 FIXME("Tried to get instance from wrong thread\n"); 00747 continue; 00748 } 00749 break; 00750 } 00751 } 00752 00753 LeaveCriticalSection(&WDML_CritSect); 00754 00755 if (!pInstance) 00756 WARN("Instance entry missing for id %04x\n", instId); 00757 return pInstance; 00758 } 00759 00760 /****************************************************************** 00761 * WDML_GetInstanceFromWnd 00762 * 00763 * 00764 */ 00765 WDML_INSTANCE* WDML_GetInstanceFromWnd(HWND hWnd) 00766 { 00767 return (WDML_INSTANCE*)GetWindowLongPtrW(hWnd, GWL_WDML_INSTANCE); 00768 } 00769 00770 /****************************************************************************** 00771 * DdeGetLastError [USER32.@] Gets most recent error code 00772 * 00773 * PARAMS 00774 * idInst [I] Instance identifier 00775 * 00776 * RETURNS 00777 * Last error code 00778 */ 00779 UINT WINAPI DdeGetLastError(DWORD idInst) 00780 { 00781 DWORD error_code; 00782 WDML_INSTANCE* pInstance; 00783 00784 /* First check instance 00785 */ 00786 pInstance = WDML_GetInstance(idInst); 00787 if (pInstance == NULL) 00788 { 00789 error_code = DMLERR_INVALIDPARAMETER; 00790 } 00791 else 00792 { 00793 error_code = pInstance->lastError; 00794 pInstance->lastError = 0; 00795 } 00796 00797 return error_code; 00798 } 00799 00800 /****************************************************************** 00801 * WDML_SetAllLastError 00802 * 00803 * 00804 */ 00805 static void WDML_SetAllLastError(DWORD lastError) 00806 { 00807 DWORD threadID; 00808 WDML_INSTANCE* pInstance; 00809 threadID = GetCurrentThreadId(); 00810 pInstance = WDML_InstanceList; 00811 while (pInstance) 00812 { 00813 if (pInstance->threadID == threadID) 00814 pInstance->lastError = lastError; 00815 pInstance = pInstance->next; 00816 } 00817 } 00818 00819 /* ================================================================ 00820 * 00821 * String management 00822 * 00823 * ================================================================ */ 00824 00825 00826 /****************************************************************** 00827 * WDML_FindNode 00828 * 00829 * 00830 */ 00831 static HSZNode* WDML_FindNode(WDML_INSTANCE* pInstance, HSZ hsz) 00832 { 00833 HSZNode* pNode; 00834 00835 if (pInstance == NULL) return NULL; 00836 00837 for (pNode = pInstance->nodeList; pNode != NULL; pNode = pNode->next) 00838 { 00839 if (pNode->hsz == hsz) break; 00840 } 00841 if (!pNode) WARN("HSZ %p not found\n", hsz); 00842 return pNode; 00843 } 00844 00845 /****************************************************************** 00846 * WDML_MakeAtomFromHsz 00847 * 00848 * Creates a global atom from an existing HSZ 00849 * Generally used before sending an HSZ as an atom to a remote app 00850 */ 00851 ATOM WDML_MakeAtomFromHsz(HSZ hsz) 00852 { 00853 WCHAR nameBuffer[MAX_BUFFER_LEN]; 00854 00855 if (GetAtomNameW(HSZ2ATOM(hsz), nameBuffer, MAX_BUFFER_LEN)) 00856 return GlobalAddAtomW(nameBuffer); 00857 WARN("HSZ %p not found\n", hsz); 00858 return 0; 00859 } 00860 00861 /****************************************************************** 00862 * WDML_MakeHszFromAtom 00863 * 00864 * Creates a HSZ from an existing global atom 00865 * Generally used while receiving a global atom and transforming it 00866 * into an HSZ 00867 */ 00868 HSZ WDML_MakeHszFromAtom(const WDML_INSTANCE* pInstance, ATOM atom) 00869 { 00870 WCHAR nameBuffer[MAX_BUFFER_LEN]; 00871 00872 if (!atom) return NULL; 00873 00874 if (GlobalGetAtomNameW(atom, nameBuffer, MAX_BUFFER_LEN)) 00875 { 00876 TRACE("%x => %s\n", atom, debugstr_w(nameBuffer)); 00877 return DdeCreateStringHandleW(pInstance->instanceID, nameBuffer, CP_WINUNICODE); 00878 } 00879 WARN("ATOM 0x%x not found\n", atom); 00880 return 0; 00881 } 00882 00883 /****************************************************************** 00884 * WDML_IncHSZ 00885 * 00886 * 00887 */ 00888 BOOL WDML_IncHSZ(WDML_INSTANCE* pInstance, HSZ hsz) 00889 { 00890 HSZNode* pNode; 00891 00892 pNode = WDML_FindNode(pInstance, hsz); 00893 if (!pNode) return FALSE; 00894 00895 pNode->refCount++; 00896 return TRUE; 00897 } 00898 00899 /****************************************************************************** 00900 * WDML_DecHSZ (INTERNAL) 00901 * 00902 * Decrease the ref count of an HSZ. If it reaches 0, the node is removed from the list 00903 * of HSZ nodes 00904 * Returns -1 is the HSZ isn't found, otherwise it's the current (after --) of the ref count 00905 */ 00906 BOOL WDML_DecHSZ(WDML_INSTANCE* pInstance, HSZ hsz) 00907 { 00908 HSZNode* pPrev = NULL; 00909 HSZNode* pCurrent; 00910 00911 for (pCurrent = pInstance->nodeList; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next) 00912 { 00913 /* If we found the node we were looking for and its ref count is one, 00914 * we can remove it 00915 */ 00916 if (pCurrent->hsz == hsz) 00917 { 00918 if (--pCurrent->refCount == 0) 00919 { 00920 if (pCurrent == pInstance->nodeList) 00921 { 00922 pInstance->nodeList = pCurrent->next; 00923 } 00924 else 00925 { 00926 pPrev->next = pCurrent->next; 00927 } 00928 HeapFree(GetProcessHeap(), 0, pCurrent); 00929 DeleteAtom(HSZ2ATOM(hsz)); 00930 } 00931 return TRUE; 00932 } 00933 } 00934 WARN("HSZ %p not found\n", hsz); 00935 00936 return FALSE; 00937 } 00938 00939 /****************************************************************************** 00940 * WDML_FreeAllHSZ (INTERNAL) 00941 * 00942 * Frees up all the strings still allocated in the list and 00943 * remove all the nodes from the list of HSZ nodes. 00944 */ 00945 void WDML_FreeAllHSZ(WDML_INSTANCE* pInstance) 00946 { 00947 /* Free any strings created in this instance. 00948 */ 00949 while (pInstance->nodeList != NULL) 00950 { 00951 DdeFreeStringHandle(pInstance->instanceID, pInstance->nodeList->hsz); 00952 } 00953 } 00954 00955 /****************************************************************************** 00956 * InsertHSZNode (INTERNAL) 00957 * 00958 * Insert a node to the head of the list. 00959 */ 00960 static void WDML_InsertHSZNode(WDML_INSTANCE* pInstance, HSZ hsz) 00961 { 00962 if (hsz != 0) 00963 { 00964 HSZNode* pNew = NULL; 00965 /* Create a new node for this HSZ. 00966 */ 00967 pNew = HeapAlloc(GetProcessHeap(), 0, sizeof(HSZNode)); 00968 if (pNew != NULL) 00969 { 00970 pNew->hsz = hsz; 00971 pNew->next = pInstance->nodeList; 00972 pNew->refCount = 1; 00973 pInstance->nodeList = pNew; 00974 } 00975 else 00976 { 00977 ERR("Primary HSZ Node allocation failed - out of memory\n"); 00978 } 00979 } 00980 } 00981 00982 /****************************************************************** 00983 * WDML_QueryString 00984 * 00985 * 00986 */ 00987 static int WDML_QueryString(WDML_INSTANCE* pInstance, HSZ hsz, LPVOID ptr, DWORD cchMax, 00988 int codepage) 00989 { 00990 WCHAR pString[MAX_BUFFER_LEN]; 00991 int ret; 00992 /* If psz is null, we have to return only the length 00993 * of the string. 00994 */ 00995 if (ptr == NULL) 00996 { 00997 ptr = pString; 00998 cchMax = MAX_BUFFER_LEN; 00999 } 01000 01001 /* if there is no input windows returns a NULL string */ 01002 if (hsz == NULL) 01003 { 01004 CHAR *t_ptr = ptr; 01005 *t_ptr = '\0'; 01006 return 1; 01007 } 01008 01009 switch (codepage) 01010 { 01011 case CP_WINANSI: 01012 ret = GetAtomNameA(HSZ2ATOM(hsz), ptr, cchMax); 01013 break; 01014 case CP_WINUNICODE: 01015 ret = GetAtomNameW(HSZ2ATOM(hsz), ptr, cchMax); 01016 break; 01017 default: 01018 ERR("Unknown code page %d\n", codepage); 01019 ret = 0; 01020 } 01021 return ret; 01022 } 01023 01024 /***************************************************************** 01025 * DdeQueryStringA [USER32.@] 01026 */ 01027 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage) 01028 { 01029 DWORD ret = 0; 01030 WDML_INSTANCE* pInstance; 01031 01032 TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage); 01033 01034 /* First check instance 01035 */ 01036 pInstance = WDML_GetInstance(idInst); 01037 if (pInstance != NULL) 01038 { 01039 if (iCodePage == 0) iCodePage = CP_WINANSI; 01040 ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage); 01041 } 01042 01043 TRACE("returning %d (%s)\n", ret, debugstr_a(psz)); 01044 return ret; 01045 } 01046 01047 /***************************************************************** 01048 * DdeQueryStringW [USER32.@] 01049 */ 01050 01051 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage) 01052 { 01053 DWORD ret = 0; 01054 WDML_INSTANCE* pInstance; 01055 01056 TRACE("(%d, %p, %p, %d, %d)\n", idInst, hsz, psz, cchMax, iCodePage); 01057 01058 /* First check instance 01059 */ 01060 pInstance = WDML_GetInstance(idInst); 01061 if (pInstance != NULL) 01062 { 01063 if (iCodePage == 0) iCodePage = CP_WINUNICODE; 01064 ret = WDML_QueryString(pInstance, hsz, psz, cchMax, iCodePage); 01065 } 01066 01067 TRACE("returning %d (%s)\n", ret, debugstr_w(psz)); 01068 return ret; 01069 } 01070 01071 /****************************************************************** 01072 * DML_CreateString 01073 * 01074 * 01075 */ 01076 static HSZ WDML_CreateString(WDML_INSTANCE* pInstance, LPCVOID ptr, int codepage) 01077 { 01078 HSZ hsz; 01079 01080 switch (codepage) 01081 { 01082 case CP_WINANSI: 01083 hsz = ATOM2HSZ(AddAtomA(ptr)); 01084 TRACE("added atom %s with HSZ %p,\n", debugstr_a(ptr), hsz); 01085 break; 01086 case CP_WINUNICODE: 01087 hsz = ATOM2HSZ(AddAtomW(ptr)); 01088 TRACE("added atom %s with HSZ %p,\n", debugstr_w(ptr), hsz); 01089 break; 01090 default: 01091 ERR("Unknown code page %d\n", codepage); 01092 return 0; 01093 } 01094 WDML_InsertHSZNode(pInstance, hsz); 01095 return hsz; 01096 } 01097 01098 /***************************************************************** 01099 * DdeCreateStringHandleA [USER32.@] 01100 * 01101 * See DdeCreateStringHandleW. 01102 */ 01103 HSZ WINAPI DdeCreateStringHandleA(DWORD idInst, LPCSTR psz, INT codepage) 01104 { 01105 HSZ hsz = 0; 01106 WDML_INSTANCE* pInstance; 01107 01108 TRACE("(%d,%s,%d)\n", idInst, debugstr_a(psz), codepage); 01109 01110 pInstance = WDML_GetInstance(idInst); 01111 if (pInstance == NULL) 01112 WDML_SetAllLastError(DMLERR_INVALIDPARAMETER); 01113 else 01114 { 01115 if (codepage == 0) codepage = CP_WINANSI; 01116 hsz = WDML_CreateString(pInstance, psz, codepage); 01117 } 01118 01119 return hsz; 01120 } 01121 01122 01123 /****************************************************************************** 01124 * DdeCreateStringHandleW [USER32.@] Creates handle to identify string 01125 * 01126 * PARAMS 01127 * idInst [I] Instance identifier 01128 * psz [I] Pointer to string 01129 * codepage [I] Code page identifier 01130 * RETURNS 01131 * Success: String handle 01132 * Failure: 0 01133 */ 01134 HSZ WINAPI DdeCreateStringHandleW(DWORD idInst, LPCWSTR psz, INT codepage) 01135 { 01136 WDML_INSTANCE* pInstance; 01137 HSZ hsz = 0; 01138 01139 pInstance = WDML_GetInstance(idInst); 01140 if (pInstance == NULL) 01141 WDML_SetAllLastError(DMLERR_INVALIDPARAMETER); 01142 else 01143 { 01144 if (codepage == 0) codepage = CP_WINUNICODE; 01145 hsz = WDML_CreateString(pInstance, psz, codepage); 01146 } 01147 01148 return hsz; 01149 } 01150 01151 /***************************************************************** 01152 * DdeFreeStringHandle (USER32.@) 01153 * RETURNS 01154 * success: nonzero 01155 * fail: zero 01156 */ 01157 BOOL WINAPI DdeFreeStringHandle(DWORD idInst, HSZ hsz) 01158 { 01159 WDML_INSTANCE* pInstance; 01160 BOOL ret = FALSE; 01161 01162 TRACE("(%d,%p):\n", idInst, hsz); 01163 01164 /* First check instance 01165 */ 01166 pInstance = WDML_GetInstance(idInst); 01167 if (pInstance) 01168 ret = WDML_DecHSZ(pInstance, hsz); 01169 01170 return ret; 01171 } 01172 01173 /***************************************************************** 01174 * DdeKeepStringHandle (USER32.@) 01175 * 01176 * RETURNS 01177 * success: nonzero 01178 * fail: zero 01179 */ 01180 BOOL WINAPI DdeKeepStringHandle(DWORD idInst, HSZ hsz) 01181 { 01182 WDML_INSTANCE* pInstance; 01183 BOOL ret = FALSE; 01184 01185 TRACE("(%d,%p):\n", idInst, hsz); 01186 01187 /* First check instance 01188 */ 01189 pInstance = WDML_GetInstance(idInst); 01190 if (pInstance) 01191 ret = WDML_IncHSZ(pInstance, hsz); 01192 01193 return ret; 01194 } 01195 01196 /***************************************************************** 01197 * DdeCmpStringHandles (USER32.@) 01198 * 01199 * Compares the value of two string handles. This comparison is 01200 * not case sensitive. 01201 * 01202 * PARAMS 01203 * hsz1 [I] Handle to the first string 01204 * hsz2 [I] Handle to the second string 01205 * 01206 * RETURNS 01207 * -1 The value of hsz1 is zero or less than hsz2 01208 * 0 The values of hsz 1 and 2 are the same or both zero. 01209 * 1 The value of hsz2 is zero of less than hsz1 01210 */ 01211 INT WINAPI DdeCmpStringHandles(HSZ hsz1, HSZ hsz2) 01212 { 01213 WCHAR psz1[MAX_BUFFER_LEN]; 01214 WCHAR psz2[MAX_BUFFER_LEN]; 01215 int ret = 0; 01216 int ret1, ret2; 01217 01218 ret1 = GetAtomNameW(HSZ2ATOM(hsz1), psz1, MAX_BUFFER_LEN); 01219 ret2 = GetAtomNameW(HSZ2ATOM(hsz2), psz2, MAX_BUFFER_LEN); 01220 01221 TRACE("(%p<%s> %p<%s>);\n", hsz1, debugstr_w(psz1), hsz2, debugstr_w(psz2)); 01222 01223 /* Make sure we found both strings. */ 01224 if (ret1 == 0 && ret2 == 0) 01225 { 01226 /* If both are not found, return both "zero strings". */ 01227 ret = 0; 01228 } 01229 else if (ret1 == 0) 01230 { 01231 /* If hsz1 is a not found, return hsz1 is "zero string". */ 01232 ret = -1; 01233 } 01234 else if (ret2 == 0) 01235 { 01236 /* If hsz2 is a not found, return hsz2 is "zero string". */ 01237 ret = 1; 01238 } 01239 else 01240 { 01241 /* Compare the two strings we got (case insensitive). */ 01242 ret = lstrcmpiW(psz1, psz2); 01243 /* Since strcmp returns any number smaller than 01244 * 0 when the first string is found to be less than 01245 * the second one we must make sure we are returning 01246 * the proper values. 01247 */ 01248 if (ret < 0) 01249 { 01250 ret = -1; 01251 } 01252 else if (ret > 0) 01253 { 01254 ret = 1; 01255 } 01256 } 01257 01258 return ret; 01259 } 01260 01261 /* ================================================================ 01262 * 01263 * Data handle management 01264 * 01265 * ================================================================ */ 01266 01267 /***************************************************************** 01268 * DdeCreateDataHandle (USER32.@) 01269 */ 01270 HDDEDATA WINAPI DdeCreateDataHandle(DWORD idInst, LPBYTE pSrc, DWORD cb, DWORD cbOff, 01271 HSZ hszItem, UINT wFmt, UINT afCmd) 01272 { 01273 01274 /* Other than check for validity we will ignore for now idInst, hszItem. 01275 * The purpose of these arguments still need to be investigated. 01276 */ 01277 01278 WDML_INSTANCE* pInstance; 01279 HGLOBAL hMem; 01280 LPBYTE pByte; 01281 DDE_DATAHANDLE_HEAD* pDdh; 01282 WCHAR psz[MAX_BUFFER_LEN]; 01283 01284 pInstance = WDML_GetInstance(idInst); 01285 if (pInstance == NULL) 01286 { 01287 WDML_SetAllLastError(DMLERR_INVALIDPARAMETER); 01288 return NULL; 01289 } 01290 01291 if (!GetAtomNameW(HSZ2ATOM(hszItem), psz, MAX_BUFFER_LEN)) 01292 { 01293 psz[0] = HSZ2ATOM(hszItem); 01294 psz[1] = 0; 01295 } 01296 01297 TRACE("(%d,%p,cb %d, cbOff %d,%p <%s>,fmt %04x,%x)\n", 01298 idInst, pSrc, cb, cbOff, hszItem, debugstr_w(psz), wFmt, afCmd); 01299 01300 if (afCmd != 0 && afCmd != HDATA_APPOWNED) 01301 return 0; 01302 01303 /* we use the first 4 bytes to store the size */ 01304 if (!(hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cb + cbOff + sizeof(DDE_DATAHANDLE_HEAD)))) 01305 { 01306 ERR("GlobalAlloc failed\n"); 01307 return 0; 01308 } 01309 01310 pDdh = GlobalLock(hMem); 01311 if (!pDdh) 01312 { 01313 GlobalFree(hMem); 01314 return 0; 01315 } 01316 01317 pDdh->cfFormat = wFmt; 01318 pDdh->bAppOwned = (afCmd == HDATA_APPOWNED); 01319 01320 pByte = (LPBYTE)(pDdh + 1); 01321 if (pSrc) 01322 { 01323 memcpy(pByte, pSrc + cbOff, cb); 01324 } 01325 GlobalUnlock(hMem); 01326 01327 TRACE("=> %p\n", hMem); 01328 return hMem; 01329 } 01330 01331 /***************************************************************** 01332 * 01333 * DdeAddData (USER32.@) 01334 */ 01335 HDDEDATA WINAPI DdeAddData(HDDEDATA hData, LPBYTE pSrc, DWORD cb, DWORD cbOff) 01336 { 01337 DWORD old_sz, new_sz; 01338 LPBYTE pDst; 01339 01340 TRACE("(%p,%p,cb %d, cbOff %d)\n", hData, pSrc, cb, cbOff); 01341 01342 pDst = DdeAccessData(hData, &old_sz); 01343 if (!pDst) return 0; 01344 01345 new_sz = cb + cbOff; 01346 if (new_sz > old_sz) 01347 { 01348 DdeUnaccessData(hData); 01349 hData = GlobalReAlloc(hData, new_sz + sizeof(DDE_DATAHANDLE_HEAD), 01350 GMEM_MOVEABLE | GMEM_DDESHARE); 01351 pDst = DdeAccessData(hData, &old_sz); 01352 } 01353 01354 if (!pDst) return 0; 01355 01356 memcpy(pDst + cbOff, pSrc, cb); 01357 DdeUnaccessData(hData); 01358 return hData; 01359 } 01360 01361 /****************************************************************************** 01362 * DdeGetData [USER32.@] Copies data from DDE object to local buffer 01363 * 01364 * 01365 * PARAMS 01366 * hData [I] Handle to DDE object 01367 * pDst [I] Pointer to destination buffer 01368 * cbMax [I] Amount of data to copy 01369 * cbOff [I] Offset to beginning of data 01370 * 01371 * RETURNS 01372 * Size of memory object associated with handle 01373 */ 01374 DWORD WINAPI DdeGetData(HDDEDATA hData, LPBYTE pDst, DWORD cbMax, DWORD cbOff) 01375 { 01376 DWORD dwSize, dwRet; 01377 LPBYTE pByte; 01378 01379 TRACE("(%p,%p,%d,%d)\n", hData, pDst, cbMax, cbOff); 01380 01381 pByte = DdeAccessData(hData, &dwSize); 01382 01383 if (pByte) 01384 { 01385 if (!pDst) 01386 { 01387 dwRet = dwSize; 01388 } 01389 else if (cbOff + cbMax < dwSize) 01390 { 01391 dwRet = cbMax; 01392 } 01393 else if (cbOff < dwSize) 01394 { 01395 dwRet = dwSize - cbOff; 01396 } 01397 else 01398 { 01399 dwRet = 0; 01400 } 01401 if (pDst && dwRet != 0) 01402 { 01403 memcpy(pDst, pByte + cbOff, dwRet); 01404 } 01405 DdeUnaccessData(hData); 01406 } 01407 else 01408 { 01409 dwRet = 0; 01410 } 01411 return dwRet; 01412 } 01413 01414 /***************************************************************** 01415 * DdeAccessData (USER32.@) 01416 */ 01417 LPBYTE WINAPI DdeAccessData(HDDEDATA hData, LPDWORD pcbDataSize) 01418 { 01419 HGLOBAL hMem = hData; 01420 DDE_DATAHANDLE_HEAD* pDdh; 01421 01422 TRACE("(%p,%p)\n", hData, pcbDataSize); 01423 01424 pDdh = GlobalLock(hMem); 01425 if (pDdh == NULL) 01426 { 01427 ERR("Failed on GlobalLock(%p)\n", hMem); 01428 return 0; 01429 } 01430 01431 if (pcbDataSize != NULL) 01432 { 01433 *pcbDataSize = GlobalSize(hMem) - sizeof(DDE_DATAHANDLE_HEAD); 01434 } 01435 TRACE("=> %p (%lu) fmt %04x\n", pDdh + 1, GlobalSize(hMem) - sizeof(DDE_DATAHANDLE_HEAD), pDdh->cfFormat); 01436 return (LPBYTE)(pDdh + 1); 01437 } 01438 01439 /***************************************************************** 01440 * DdeUnaccessData (USER32.@) 01441 */ 01442 BOOL WINAPI DdeUnaccessData(HDDEDATA hData) 01443 { 01444 HGLOBAL hMem = hData; 01445 01446 TRACE("(%p)\n", hData); 01447 01448 GlobalUnlock(hMem); 01449 01450 return TRUE; 01451 } 01452 01453 /***************************************************************** 01454 * DdeFreeDataHandle (USER32.@) 01455 */ 01456 BOOL WINAPI DdeFreeDataHandle(HDDEDATA hData) 01457 { 01458 TRACE("(%p)\n", hData); 01459 01460 /* 1 is the handle value returned by an asynchronous operation. */ 01461 if (hData == (HDDEDATA)1) 01462 return TRUE; 01463 01464 return GlobalFree(hData) == 0; 01465 } 01466 01467 /****************************************************************** 01468 * WDML_IsAppOwned 01469 * 01470 * 01471 */ 01472 BOOL WDML_IsAppOwned(HDDEDATA hData) 01473 { 01474 DDE_DATAHANDLE_HEAD* pDdh; 01475 BOOL ret = FALSE; 01476 01477 pDdh = GlobalLock(hData); 01478 if (pDdh != NULL) 01479 { 01480 ret = pDdh->bAppOwned; 01481 GlobalUnlock(hData); 01482 } 01483 return ret; 01484 } 01485 01486 /* ================================================================ 01487 * 01488 * Global <=> Data handle management 01489 * 01490 * ================================================================ */ 01491 01492 /* Note: we use a DDEDATA, but layout of DDEDATA, DDEADVISE and DDEPOKE structures is similar: 01493 * offset size 01494 * (bytes) (bits) comment 01495 * 0 16 bit fields for options (release, ackreq, response...) 01496 * 2 16 clipboard format 01497 * 4 ? data to be used 01498 */ 01499 HDDEDATA WDML_Global2DataHandle(WDML_CONV* pConv, HGLOBAL hMem, WINE_DDEHEAD* p) 01500 { 01501 DDEDATA* pDd; 01502 HDDEDATA ret = 0; 01503 DWORD size; 01504 01505 if (hMem) 01506 { 01507 pDd = GlobalLock(hMem); 01508 size = GlobalSize(hMem) - sizeof(WINE_DDEHEAD); 01509 if (pDd) 01510 { 01511 if (p) memcpy(p, pDd, sizeof(WINE_DDEHEAD)); 01512 switch (pDd->cfFormat) 01513 { 01514 default: 01515 FIXME("Unsupported format (%04x) for data %p, passing raw information\n", 01516 pDd->cfFormat, hMem); 01517 /* fall thru */ 01518 case 0: 01519 case CF_TEXT: 01520 ret = DdeCreateDataHandle(pConv->instance->instanceID, pDd->Value, size, 0, 0, pDd->cfFormat, 0); 01521 break; 01522 case CF_BITMAP: 01523 if (size >= sizeof(BITMAP)) 01524 { 01525 BITMAP* bmp = (BITMAP*)pDd->Value; 01526 int count = bmp->bmWidthBytes * bmp->bmHeight * bmp->bmPlanes; 01527 if (size >= sizeof(BITMAP) + count) 01528 { 01529 HBITMAP hbmp; 01530 01531 if ((hbmp = CreateBitmap(bmp->bmWidth, bmp->bmHeight, 01532 bmp->bmPlanes, bmp->bmBitsPixel, 01533 pDd->Value + sizeof(BITMAP)))) 01534 { 01535 ret = DdeCreateDataHandle(pConv->instance->instanceID, (LPBYTE)&hbmp, sizeof(hbmp), 01536 0, 0, CF_BITMAP, 0); 01537 } 01538 else ERR("Can't create bmp\n"); 01539 } 01540 else 01541 { 01542 ERR("Wrong count: %u / %d\n", size, count); 01543 } 01544 } else ERR("No bitmap header\n"); 01545 break; 01546 } 01547 GlobalUnlock(hMem); 01548 } 01549 } 01550 return ret; 01551 } 01552 01553 /****************************************************************** 01554 * WDML_DataHandle2Global 01555 * 01556 * 01557 */ 01558 HGLOBAL WDML_DataHandle2Global(HDDEDATA hDdeData, BOOL fResponse, BOOL fRelease, 01559 BOOL fDeferUpd, BOOL fAckReq) 01560 { 01561 DDE_DATAHANDLE_HEAD* pDdh; 01562 DWORD dwSize; 01563 HGLOBAL hMem = 0; 01564 01565 dwSize = GlobalSize(hDdeData) - sizeof(DDE_DATAHANDLE_HEAD); 01566 pDdh = GlobalLock(hDdeData); 01567 if (dwSize && pDdh) 01568 { 01569 WINE_DDEHEAD* wdh = NULL; 01570 01571 switch (pDdh->cfFormat) 01572 { 01573 default: 01574 FIXME("Unsupported format (%04x) for data %p, passing raw information\n", 01575 pDdh->cfFormat, hDdeData); 01576 /* fall thru */ 01577 case 0: 01578 case CF_TEXT: 01579 hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(WINE_DDEHEAD) + dwSize); 01580 if (hMem && (wdh = GlobalLock(hMem))) 01581 { 01582 memcpy(wdh + 1, pDdh + 1, dwSize); 01583 } 01584 break; 01585 case CF_BITMAP: 01586 if (dwSize >= sizeof(HBITMAP)) 01587 { 01588 BITMAP bmp; 01589 DWORD count; 01590 HBITMAP hbmp = *(HBITMAP*)(pDdh + 1); 01591 01592 if (GetObjectW(hbmp, sizeof(bmp), &bmp)) 01593 { 01594 count = bmp.bmWidthBytes * bmp.bmHeight; 01595 hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 01596 sizeof(WINE_DDEHEAD) + sizeof(bmp) + count); 01597 if (hMem && (wdh = GlobalLock(hMem))) 01598 { 01599 memcpy(wdh + 1, &bmp, sizeof(bmp)); 01600 GetBitmapBits(hbmp, count, ((char*)(wdh + 1)) + sizeof(bmp)); 01601 } 01602 } 01603 } 01604 break; 01605 } 01606 if (wdh) 01607 { 01608 wdh->unused = 0; 01609 wdh->fResponse = fResponse; 01610 wdh->fRelease = fRelease; 01611 wdh->fDeferUpd = fDeferUpd; 01612 wdh->fAckReq = fAckReq; 01613 wdh->cfFormat = pDdh->cfFormat; 01614 GlobalUnlock(hMem); 01615 } 01616 GlobalUnlock(hDdeData); 01617 } 01618 01619 return hMem; 01620 } 01621 01622 /* ================================================================ 01623 * 01624 * Server management 01625 * 01626 * ================================================================ */ 01627 01628 /****************************************************************** 01629 * WDML_AddServer 01630 * 01631 * 01632 */ 01633 WDML_SERVER* WDML_AddServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic) 01634 { 01635 static const WCHAR fmtW[] = {'%','s','(','0','x','%','*','x',')',0}; 01636 WDML_SERVER* pServer; 01637 WCHAR buf1[256]; 01638 WCHAR buf2[256]; 01639 01640 pServer = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_SERVER)); 01641 if (pServer == NULL) return NULL; 01642 01643 pServer->hszService = hszService; 01644 WDML_IncHSZ(pInstance, hszService); 01645 01646 DdeQueryStringW(pInstance->instanceID, hszService, buf1, 256, CP_WINUNICODE); 01647 snprintfW(buf2, 256, fmtW, buf1, 2*sizeof(ULONG_PTR), GetCurrentProcessId()); 01648 pServer->hszServiceSpec = DdeCreateStringHandleW(pInstance->instanceID, buf2, CP_WINUNICODE); 01649 01650 pServer->atomService = WDML_MakeAtomFromHsz(pServer->hszService); 01651 pServer->atomServiceSpec = WDML_MakeAtomFromHsz(pServer->hszServiceSpec); 01652 01653 pServer->filterOn = TRUE; 01654 01655 pServer->next = pInstance->servers; 01656 pInstance->servers = pServer; 01657 return pServer; 01658 } 01659 01660 /****************************************************************** 01661 * WDML_RemoveServer 01662 * 01663 * 01664 */ 01665 void WDML_RemoveServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic) 01666 { 01667 WDML_SERVER* pPrev = NULL; 01668 WDML_SERVER* pServer = NULL; 01669 WDML_CONV* pConv; 01670 WDML_CONV* pConvNext; 01671 01672 pServer = pInstance->servers; 01673 01674 while (pServer != NULL) 01675 { 01676 if (DdeCmpStringHandles(pServer->hszService, hszService) == 0) 01677 { 01678 WDML_BroadcastDDEWindows(WDML_szEventClass, WM_WDML_UNREGISTER, 01679 pServer->atomService, pServer->atomServiceSpec); 01680 /* terminate all conversations for given topic */ 01681 for (pConv = pInstance->convs[WDML_SERVER_SIDE]; pConv != NULL; pConv = pConvNext) 01682 { 01683 pConvNext = pConv->next; 01684 if (DdeCmpStringHandles(pConv->hszService, hszService) == 0) 01685 { 01686 HWND client = pConv->hwndClient, server = pConv->hwndServer; 01687 WDML_RemoveConv(pConv, WDML_SERVER_SIDE); 01688 /* don't care about return code (whether client window is present or not) */ 01689 PostMessageW(client, WM_DDE_TERMINATE, (WPARAM)server, 0); 01690 } 01691 } 01692 if (pServer == pInstance->servers) 01693 { 01694 pInstance->servers = pServer->next; 01695 } 01696 else 01697 { 01698 pPrev->next = pServer->next; 01699 } 01700 01701 DestroyWindow(pServer->hwndServer); 01702 WDML_DecHSZ(pInstance, pServer->hszServiceSpec); 01703 WDML_DecHSZ(pInstance, pServer->hszService); 01704 01705 GlobalDeleteAtom(pServer->atomService); 01706 GlobalDeleteAtom(pServer->atomServiceSpec); 01707 01708 HeapFree(GetProcessHeap(), 0, pServer); 01709 break; 01710 } 01711 01712 pPrev = pServer; 01713 pServer = pServer->next; 01714 } 01715 } 01716 01717 /***************************************************************************** 01718 * WDML_FindServer 01719 * 01720 * generic routine to return a pointer to the relevant ServiceNode 01721 * for a given service name, or NULL if the entry does not exist 01722 * 01723 */ 01724 WDML_SERVER* WDML_FindServer(WDML_INSTANCE* pInstance, HSZ hszService, HSZ hszTopic) 01725 { 01726 WDML_SERVER* pServer; 01727 01728 for (pServer = pInstance->servers; pServer != NULL; pServer = pServer->next) 01729 { 01730 if (hszService == pServer->hszService) 01731 { 01732 return pServer; 01733 } 01734 } 01735 TRACE("Service name missing\n"); 01736 return NULL; 01737 } 01738 01739 /* ================================================================ 01740 * 01741 * Conversation management 01742 * 01743 * ================================================================ */ 01744 01745 /****************************************************************** 01746 * WDML_AddConv 01747 * 01748 * 01749 */ 01750 WDML_CONV* WDML_AddConv(WDML_INSTANCE* pInstance, WDML_SIDE side, 01751 HSZ hszService, HSZ hszTopic, HWND hwndClient, HWND hwndServer) 01752 { 01753 WDML_CONV* pConv; 01754 01755 /* no conversation yet, add it */ 01756 pConv = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_CONV)); 01757 if (!pConv) return NULL; 01758 01759 pConv->instance = pInstance; 01760 WDML_IncHSZ(pInstance, pConv->hszService = hszService); 01761 WDML_IncHSZ(pInstance, pConv->hszTopic = hszTopic); 01762 pConv->magic = WDML_CONV_MAGIC; 01763 pConv->hwndServer = hwndServer; 01764 pConv->hwndClient = hwndClient; 01765 pConv->transactions = NULL; 01766 pConv->hUser = 0; 01767 pConv->wStatus = (side == WDML_CLIENT_SIDE) ? ST_CLIENT : 0L; 01768 pConv->wStatus |= pInstance->wStatus; 01769 /* check if both side of the conversation are of the same instance */ 01770 if (GetWindowThreadProcessId(hwndClient, NULL) == GetWindowThreadProcessId(hwndServer, NULL) && 01771 WDML_GetInstanceFromWnd(hwndClient) == WDML_GetInstanceFromWnd(hwndServer)) 01772 { 01773 pConv->wStatus |= ST_ISSELF; 01774 } 01775 pConv->wConvst = XST_NULL; 01776 01777 pConv->next = pInstance->convs[side]; 01778 pInstance->convs[side] = pConv; 01779 01780 TRACE("pConv->wStatus %04x pInstance(%p)\n", pConv->wStatus, pInstance); 01781 01782 return pConv; 01783 } 01784 01785 /****************************************************************** 01786 * WDML_FindConv 01787 * 01788 * 01789 */ 01790 WDML_CONV* WDML_FindConv(WDML_INSTANCE* pInstance, WDML_SIDE side, 01791 HSZ hszService, HSZ hszTopic) 01792 { 01793 WDML_CONV* pCurrent = NULL; 01794 01795 for (pCurrent = pInstance->convs[side]; pCurrent != NULL; pCurrent = pCurrent->next) 01796 { 01797 if (DdeCmpStringHandles(pCurrent->hszService, hszService) == 0 && 01798 DdeCmpStringHandles(pCurrent->hszTopic, hszTopic) == 0) 01799 { 01800 return pCurrent; 01801 } 01802 01803 } 01804 return NULL; 01805 } 01806 01807 /****************************************************************** 01808 * WDML_RemoveConv 01809 * 01810 * 01811 */ 01812 void WDML_RemoveConv(WDML_CONV* pRef, WDML_SIDE side) 01813 { 01814 WDML_CONV* pPrev = NULL; 01815 WDML_CONV* pCurrent; 01816 WDML_XACT* pXAct; 01817 WDML_XACT* pXActNext; 01818 HWND hWnd; 01819 01820 if (!pRef) 01821 return; 01822 01823 /* remove any pending transaction */ 01824 for (pXAct = pRef->transactions; pXAct != NULL; pXAct = pXActNext) 01825 { 01826 pXActNext = pXAct->next; 01827 WDML_FreeTransaction(pRef->instance, pXAct, TRUE); 01828 } 01829 01830 WDML_RemoveAllLinks(pRef->instance, pRef, side); 01831 01832 /* FIXME: should we keep the window around ? it seems so (at least on client side 01833 * to let QueryConvInfo work after conv termination, but also to implement 01834 * DdeReconnect... 01835 */ 01836 /* destroy conversation window, but first remove pConv from hWnd. 01837 * this would help the wndProc do appropriate handling upon a WM_DESTROY message 01838 */ 01839 hWnd = (side == WDML_CLIENT_SIDE) ? pRef->hwndClient : pRef->hwndServer; 01840 SetWindowLongPtrW(hWnd, GWL_WDML_CONVERSATION, 0); 01841 01842 DestroyWindow((side == WDML_CLIENT_SIDE) ? pRef->hwndClient : pRef->hwndServer); 01843 01844 WDML_DecHSZ(pRef->instance, pRef->hszService); 01845 WDML_DecHSZ(pRef->instance, pRef->hszTopic); 01846 01847 for (pCurrent = pRef->instance->convs[side]; pCurrent != NULL; pCurrent = (pPrev = pCurrent)->next) 01848 { 01849 if (pCurrent == pRef) 01850 { 01851 if (pCurrent == pRef->instance->convs[side]) 01852 { 01853 pRef->instance->convs[side] = pCurrent->next; 01854 } 01855 else 01856 { 01857 pPrev->next = pCurrent->next; 01858 } 01859 pCurrent->magic = 0; 01860 HeapFree(GetProcessHeap(), 0, pCurrent); 01861 break; 01862 } 01863 } 01864 } 01865 01866 /****************************************************************** 01867 * WDML_EnableCallback 01868 */ 01869 static BOOL WDML_EnableCallback(WDML_CONV *pConv, UINT wCmd) 01870 { 01871 if (wCmd == EC_DISABLE) 01872 { 01873 pConv->wStatus |= ST_BLOCKED; 01874 TRACE("EC_DISABLE: conv %p status flags %04x\n", pConv, pConv->wStatus); 01875 return TRUE; 01876 } 01877 01878 if (wCmd == EC_QUERYWAITING) 01879 return pConv->transactions ? TRUE : FALSE; 01880 01881 if (wCmd != EC_ENABLEALL && wCmd != EC_ENABLEONE) 01882 { 01883 FIXME("Unknown command code %04x\n", wCmd); 01884 return FALSE; 01885 } 01886 01887 if (wCmd == EC_ENABLEALL) 01888 { 01889 pConv->wStatus &= ~ST_BLOCKED; 01890 TRACE("EC_ENABLEALL: conv %p status flags %04x\n", pConv, pConv->wStatus); 01891 } 01892 01893 while (pConv->transactions) 01894 { 01895 WDML_XACT *pXAct = pConv->transactions; 01896 01897 if (pConv->wStatus & ST_CLIENT) 01898 { 01899 /* transaction should be in the queue until handled */ 01900 WDML_ClientHandle(pConv, pXAct, 0, NULL); 01901 WDML_UnQueueTransaction(pConv, pXAct); 01902 } 01903 else 01904 { 01905 /* transaction should be removed from the queue before handling */ 01906 WDML_UnQueueTransaction(pConv, pXAct); 01907 WDML_ServerHandle(pConv, pXAct); 01908 } 01909 01910 WDML_FreeTransaction(pConv->instance, pXAct, TRUE); 01911 01912 if (wCmd == EC_ENABLEONE) break; 01913 } 01914 return TRUE; 01915 } 01916 01917 /***************************************************************** 01918 * DdeEnableCallback (USER32.@) 01919 */ 01920 BOOL WINAPI DdeEnableCallback(DWORD idInst, HCONV hConv, UINT wCmd) 01921 { 01922 BOOL ret = FALSE; 01923 WDML_CONV *pConv; 01924 01925 TRACE("(%d, %p, %04x)\n", idInst, hConv, wCmd); 01926 01927 if (hConv) 01928 { 01929 pConv = WDML_GetConv(hConv, TRUE); 01930 01931 if (pConv && pConv->instance->instanceID == idInst) 01932 ret = WDML_EnableCallback(pConv, wCmd); 01933 } 01934 else 01935 { 01936 WDML_INSTANCE *pInstance = WDML_GetInstance(idInst); 01937 01938 if (!pInstance) 01939 return FALSE; 01940 01941 TRACE("adding flags %04x to instance %p\n", wCmd, pInstance); 01942 pInstance->wStatus |= wCmd; 01943 01944 if (wCmd == EC_DISABLE) 01945 { 01946 pInstance->wStatus |= ST_BLOCKED; 01947 TRACE("EC_DISABLE: inst %p status flags %04x\n", pInstance, pInstance->wStatus); 01948 } 01949 else if (wCmd == EC_ENABLEALL) 01950 { 01951 pInstance->wStatus &= ~ST_BLOCKED; 01952 TRACE("EC_ENABLEALL: inst %p status flags %04x\n", pInstance, pInstance->wStatus); 01953 } 01954 01955 ret = TRUE; 01956 01957 for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv != NULL; pConv = pConv->next) 01958 { 01959 ret = WDML_EnableCallback(pConv, wCmd); 01960 if (ret && wCmd == EC_QUERYWAITING) break; 01961 } 01962 } 01963 01964 return ret; 01965 } 01966 01967 /****************************************************************** 01968 * WDML_GetConv 01969 * 01970 * 01971 */ 01972 WDML_CONV* WDML_GetConv(HCONV hConv, BOOL checkConnected) 01973 { 01974 WDML_CONV* pConv = (WDML_CONV*)hConv; 01975 01976 /* FIXME: should do better checking */ 01977 if (pConv == NULL || pConv->magic != WDML_CONV_MAGIC) return NULL; 01978 01979 if (!pConv->instance) 01980 { 01981 WARN("wrong thread ID, no instance\n"); 01982 return NULL; 01983 } 01984 01985 if (pConv->instance->threadID != GetCurrentThreadId()) 01986 { 01987 WARN("wrong thread ID\n"); 01988 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; /* FIXME: check */ 01989 return NULL; 01990 } 01991 01992 if (checkConnected && !(pConv->wStatus & ST_CONNECTED)) 01993 { 01994 WARN("found conv but ain't connected\n"); 01995 pConv->instance->lastError = DMLERR_NO_CONV_ESTABLISHED; 01996 return NULL; 01997 } 01998 01999 return pConv; 02000 } 02001 02002 /****************************************************************** 02003 * WDML_GetConvFromWnd 02004 * 02005 * 02006 */ 02007 WDML_CONV* WDML_GetConvFromWnd(HWND hWnd) 02008 { 02009 return (WDML_CONV*)GetWindowLongPtrW(hWnd, GWL_WDML_CONVERSATION); 02010 } 02011 02012 /****************************************************************** 02013 * WDML_PostAck 02014 * 02015 * 02016 */ 02017 BOOL WDML_PostAck(WDML_CONV* pConv, WDML_SIDE side, WORD appRetCode, 02018 BOOL fBusy, BOOL fAck, UINT_PTR pmt, LPARAM lParam, UINT oldMsg) 02019 { 02020 DDEACK ddeAck; 02021 HWND from, to; 02022 02023 if (side == WDML_SERVER_SIDE) 02024 { 02025 from = pConv->hwndServer; 02026 to = pConv->hwndClient; 02027 } 02028 else 02029 { 02030 to = pConv->hwndServer; 02031 from = pConv->hwndClient; 02032 } 02033 02034 ddeAck.bAppReturnCode = appRetCode; 02035 ddeAck.reserved = 0; 02036 ddeAck.fBusy = fBusy; 02037 ddeAck.fAck = fAck; 02038 02039 TRACE("Posting a %s ack\n", ddeAck.fAck ? "positive" : "negative"); 02040 02041 lParam = (lParam) ? ReuseDDElParam(lParam, oldMsg, WM_DDE_ACK, *(WORD*)&ddeAck, pmt) : 02042 PackDDElParam(WM_DDE_ACK, *(WORD*)&ddeAck, pmt); 02043 if (!PostMessageW(to, WM_DDE_ACK, (WPARAM)from, lParam)) 02044 { 02045 pConv->wStatus &= ~ST_CONNECTED; 02046 pConv->instance->lastError = DMLERR_POSTMSG_FAILED; 02047 FreeDDElParam(WM_DDE_ACK, lParam); 02048 return FALSE; 02049 } 02050 return TRUE; 02051 } 02052 02053 /***************************************************************** 02054 * DdeSetUserHandle (USER32.@) 02055 */ 02056 BOOL WINAPI DdeSetUserHandle(HCONV hConv, DWORD id, DWORD hUser) 02057 { 02058 WDML_CONV* pConv; 02059 02060 pConv = WDML_GetConv(hConv, FALSE); 02061 if (pConv == NULL) 02062 return FALSE; 02063 02064 if (id == QID_SYNC) 02065 { 02066 pConv->hUser = hUser; 02067 } 02068 else 02069 { 02070 WDML_XACT* pXAct; 02071 02072 pXAct = WDML_FindTransaction(pConv, id); 02073 if (pXAct) 02074 { 02075 pXAct->hUser = hUser; 02076 } 02077 else 02078 { 02079 pConv->instance->lastError = DMLERR_UNFOUND_QUEUE_ID; 02080 return FALSE; 02081 } 02082 } 02083 return TRUE; 02084 } 02085 02086 /****************************************************************** 02087 * WDML_GetLocalConvInfo 02088 * 02089 * 02090 */ 02091 static BOOL WDML_GetLocalConvInfo(WDML_CONV* pConv, CONVINFO* ci, DWORD id) 02092 { 02093 BOOL ret = TRUE; 02094 WDML_LINK* pLink; 02095 WDML_SIDE side; 02096 02097 ci->hConvPartner = (pConv->wStatus & ST_ISLOCAL) ? (HCONV)((ULONG_PTR)pConv | 1) : 0; 02098 ci->hszSvcPartner = pConv->hszService; 02099 ci->hszServiceReq = pConv->hszService; /* FIXME: they shouldn't be the same, should they ? */ 02100 ci->hszTopic = pConv->hszTopic; 02101 ci->wStatus = pConv->wStatus; 02102 02103 side = (pConv->wStatus & ST_CLIENT) ? WDML_CLIENT_SIDE : WDML_SERVER_SIDE; 02104 02105 for (pLink = pConv->instance->links[side]; pLink != NULL; pLink = pLink->next) 02106 { 02107 if (pLink->hConv == (HCONV)pConv) 02108 { 02109 ci->wStatus |= ST_ADVISE; 02110 break; 02111 } 02112 } 02113 02114 /* FIXME: non handled status flags: 02115 ST_BLOCKED 02116 ST_BLOCKNEXT 02117 ST_INLIST 02118 */ 02119 02120 ci->wConvst = pConv->wConvst; /* FIXME */ 02121 02122 ci->wLastError = 0; /* FIXME: note it's not the instance last error */ 02123 ci->hConvList = 0; 02124 ci->ConvCtxt = pConv->convContext; 02125 if (ci->wStatus & ST_CLIENT) 02126 { 02127 ci->hwnd = pConv->hwndClient; 02128 ci->hwndPartner = pConv->hwndServer; 02129 } 02130 else 02131 { 02132 ci->hwnd = pConv->hwndServer; 02133 ci->hwndPartner = pConv->hwndClient; 02134 } 02135 if (id == QID_SYNC) 02136 { 02137 ci->hUser = pConv->hUser; 02138 ci->hszItem = 0; 02139 ci->wFmt = 0; 02140 ci->wType = 0; 02141 } 02142 else 02143 { 02144 WDML_XACT* pXAct; 02145 02146 pXAct = WDML_FindTransaction(pConv, id); 02147 if (pXAct) 02148 { 02149 ci->hUser = pXAct->hUser; 02150 ci->hszItem = pXAct->hszItem; 02151 ci->wFmt = pXAct->wFmt; 02152 ci->wType = pXAct->wType; 02153 } 02154 else 02155 { 02156 ret = 0; 02157 pConv->instance->lastError = DMLERR_UNFOUND_QUEUE_ID; 02158 } 02159 } 02160 return ret; 02161 } 02162 02163 /****************************************************************** 02164 * DdeQueryConvInfo (USER32.@) 02165 * 02166 * FIXME: Set last DDE error on failure. 02167 */ 02168 UINT WINAPI DdeQueryConvInfo(HCONV hConv, DWORD id, PCONVINFO lpConvInfo) 02169 { 02170 UINT ret = lpConvInfo->cb; 02171 CONVINFO ci; 02172 WDML_CONV* pConv; 02173 02174 TRACE("(%p,%x,%p)\n", hConv, id, lpConvInfo); 02175 02176 if (!hConv) 02177 { 02178 FIXME("hConv is NULL\n"); 02179 return 0; 02180 } 02181 02182 pConv = WDML_GetConv(hConv, FALSE); 02183 if (pConv != NULL) 02184 { 02185 if (!WDML_GetLocalConvInfo(pConv, &ci, id)) 02186 ret = 0; 02187 } 02188 else 02189 { 02190 if ((ULONG_PTR)hConv & 1) 02191 { 02192 pConv = WDML_GetConv((HCONV)((ULONG_PTR)hConv & ~1), FALSE); 02193 if (pConv != NULL) 02194 FIXME("Request on remote conversation information is not implemented yet\n"); 02195 } 02196 ret = 0; 02197 } 02198 02199 if (ret != 0) 02200 memcpy(lpConvInfo, &ci, min((size_t)lpConvInfo->cb, sizeof(ci))); 02201 return ret; 02202 } 02203 02204 /* ================================================================ 02205 * 02206 * Link (hot & warm) management 02207 * 02208 * ================================================================ */ 02209 02210 /****************************************************************** 02211 * WDML_AddLink 02212 * 02213 * 02214 */ 02215 void WDML_AddLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side, 02216 UINT wType, HSZ hszItem, UINT wFmt) 02217 { 02218 WDML_LINK* pLink; 02219 02220 pLink = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_LINK)); 02221 if (pLink == NULL) 02222 { 02223 ERR("OOM\n"); 02224 return; 02225 } 02226 02227 pLink->hConv = hConv; 02228 pLink->transactionType = wType; 02229 WDML_IncHSZ(pInstance, pLink->hszItem = hszItem); 02230 pLink->uFmt = wFmt; 02231 pLink->next = pInstance->links[side]; 02232 pInstance->links[side] = pLink; 02233 } 02234 02235 /****************************************************************** 02236 * WDML_RemoveLink 02237 * 02238 * 02239 */ 02240 void WDML_RemoveLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side, 02241 HSZ hszItem, UINT uFmt) 02242 { 02243 WDML_LINK* pPrev = NULL; 02244 WDML_LINK* pCurrent = NULL; 02245 02246 pCurrent = pInstance->links[side]; 02247 02248 while (pCurrent != NULL) 02249 { 02250 if (pCurrent->hConv == hConv && 02251 DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 && 02252 pCurrent->uFmt == uFmt) 02253 { 02254 if (pCurrent == pInstance->links[side]) 02255 { 02256 pInstance->links[side] = pCurrent->next; 02257 } 02258 else 02259 { 02260 pPrev->next = pCurrent->next; 02261 } 02262 02263 WDML_DecHSZ(pInstance, pCurrent->hszItem); 02264 HeapFree(GetProcessHeap(), 0, pCurrent); 02265 break; 02266 } 02267 02268 pPrev = pCurrent; 02269 pCurrent = pCurrent->next; 02270 } 02271 } 02272 02273 /* this function is called to remove all links related to the conv. 02274 It should be called from both client and server when terminating 02275 the conversation. 02276 */ 02277 /****************************************************************** 02278 * WDML_RemoveAllLinks 02279 * 02280 * 02281 */ 02282 void WDML_RemoveAllLinks(WDML_INSTANCE* pInstance, WDML_CONV* pConv, WDML_SIDE side) 02283 { 02284 WDML_LINK* pPrev = NULL; 02285 WDML_LINK* pCurrent = NULL; 02286 WDML_LINK* pNext = NULL; 02287 02288 pCurrent = pInstance->links[side]; 02289 02290 while (pCurrent != NULL) 02291 { 02292 if (pCurrent->hConv == (HCONV)pConv) 02293 { 02294 if (pCurrent == pInstance->links[side]) 02295 { 02296 pInstance->links[side] = pCurrent->next; 02297 pNext = pCurrent->next; 02298 } 02299 else 02300 { 02301 pPrev->next = pCurrent->next; 02302 pNext = pCurrent->next; 02303 } 02304 02305 WDML_DecHSZ(pInstance, pCurrent->hszItem); 02306 02307 HeapFree(GetProcessHeap(), 0, pCurrent); 02308 pCurrent = NULL; 02309 } 02310 02311 if (pCurrent) 02312 { 02313 pPrev = pCurrent; 02314 pCurrent = pCurrent->next; 02315 } 02316 else 02317 { 02318 pCurrent = pNext; 02319 } 02320 } 02321 } 02322 02323 /****************************************************************** 02324 * WDML_FindLink 02325 * 02326 * 02327 */ 02328 WDML_LINK* WDML_FindLink(WDML_INSTANCE* pInstance, HCONV hConv, WDML_SIDE side, 02329 HSZ hszItem, BOOL use_fmt, UINT uFmt) 02330 { 02331 WDML_LINK* pCurrent = NULL; 02332 02333 for (pCurrent = pInstance->links[side]; pCurrent != NULL; pCurrent = pCurrent->next) 02334 { 02335 /* we don't need to check for transaction type as it can be altered */ 02336 02337 if (pCurrent->hConv == hConv && 02338 DdeCmpStringHandles(pCurrent->hszItem, hszItem) == 0 && 02339 (!use_fmt || pCurrent->uFmt == uFmt)) 02340 { 02341 break; 02342 } 02343 02344 } 02345 02346 return pCurrent; 02347 } 02348 02349 /* ================================================================ 02350 * 02351 * Transaction management 02352 * 02353 * ================================================================ */ 02354 02355 /****************************************************************** 02356 * WDML_AllocTransaction 02357 * 02358 * Alloc a transaction structure for handling the message ddeMsg 02359 */ 02360 WDML_XACT* WDML_AllocTransaction(WDML_INSTANCE* pInstance, UINT ddeMsg, 02361 UINT wFmt, HSZ hszItem) 02362 { 02363 WDML_XACT* pXAct; 02364 static WORD tid = 1; /* FIXME: wrap around */ 02365 02366 pXAct = HeapAlloc(GetProcessHeap(), 0, sizeof(WDML_XACT)); 02367 if (!pXAct) 02368 { 02369 pInstance->lastError = DMLERR_MEMORY_ERROR; 02370 return NULL; 02371 } 02372 02373 pXAct->xActID = tid++; 02374 pXAct->ddeMsg = ddeMsg; 02375 pXAct->hDdeData = 0; 02376 pXAct->hUser = 0; 02377 pXAct->next = NULL; 02378 pXAct->wType = 0; 02379 pXAct->wFmt = wFmt; 02380 if ((pXAct->hszItem = hszItem)) WDML_IncHSZ(pInstance, pXAct->hszItem); 02381 pXAct->atom = 0; 02382 pXAct->hMem = 0; 02383 pXAct->lParam = 0; 02384 02385 return pXAct; 02386 } 02387 02388 /****************************************************************** 02389 * WDML_QueueTransaction 02390 * 02391 * Adds a transaction to the list of transaction 02392 */ 02393 void WDML_QueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct) 02394 { 02395 WDML_XACT** pt; 02396 02397 /* advance to last in queue */ 02398 for (pt = &pConv->transactions; *pt != NULL; pt = &(*pt)->next); 02399 *pt = pXAct; 02400 } 02401 02402 /****************************************************************** 02403 * WDML_UnQueueTransaction 02404 * 02405 * 02406 */ 02407 BOOL WDML_UnQueueTransaction(WDML_CONV* pConv, WDML_XACT* pXAct) 02408 { 02409 WDML_XACT** pt; 02410 02411 for (pt = &pConv->transactions; *pt; pt = &(*pt)->next) 02412 { 02413 if (*pt == pXAct) 02414 { 02415 *pt = pXAct->next; 02416 return TRUE; 02417 } 02418 } 02419 return FALSE; 02420 } 02421 02422 /****************************************************************** 02423 * WDML_FreeTransaction 02424 * 02425 * 02426 */ 02427 void WDML_FreeTransaction(WDML_INSTANCE* pInstance, WDML_XACT* pXAct, BOOL doFreePmt) 02428 { 02429 /* free pmt(s) in pXAct too. check against one for not deleting TRUE return values */ 02430 if (doFreePmt && (ULONG_PTR)pXAct->hMem > 1) 02431 { 02432 GlobalFree(pXAct->hMem); 02433 } 02434 if (pXAct->hszItem) WDML_DecHSZ(pInstance, pXAct->hszItem); 02435 02436 HeapFree(GetProcessHeap(), 0, pXAct); 02437 } 02438 02439 /****************************************************************** 02440 * WDML_FindTransaction 02441 * 02442 * 02443 */ 02444 WDML_XACT* WDML_FindTransaction(WDML_CONV* pConv, DWORD tid) 02445 { 02446 WDML_XACT* pXAct; 02447 02448 tid = HIWORD(tid); 02449 for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next) 02450 { 02451 if (pXAct->xActID == tid) 02452 break; 02453 } 02454 return pXAct; 02455 } 02456 02457 /* ================================================================ 02458 * 02459 * Information broadcast across DDEML implementations 02460 * 02461 * ================================================================ */ 02462 02463 struct tagWDML_BroadcastPmt 02464 { 02465 LPCWSTR clsName; 02466 UINT uMsg; 02467 WPARAM wParam; 02468 LPARAM lParam; 02469 }; 02470 02471 /****************************************************************** 02472 * WDML_BroadcastEnumProc 02473 * 02474 * 02475 */ 02476 static BOOL CALLBACK WDML_BroadcastEnumProc(HWND hWnd, LPARAM lParam) 02477 { 02478 struct tagWDML_BroadcastPmt* s = (struct tagWDML_BroadcastPmt*)lParam; 02479 WCHAR buffer[128]; 02480 02481 if (GetClassNameW(hWnd, buffer, 128) > 0 && 02482 lstrcmpiW(buffer, s->clsName) == 0) 02483 { 02484 PostMessageW(hWnd, s->uMsg, s->wParam, s->lParam); 02485 } 02486 return TRUE; 02487 } 02488 02489 /****************************************************************** 02490 * WDML_BroadcastDDEWindows 02491 * 02492 * 02493 */ 02494 void WDML_BroadcastDDEWindows(LPCWSTR clsName, UINT uMsg, WPARAM wParam, LPARAM lParam) 02495 { 02496 struct tagWDML_BroadcastPmt s; 02497 02498 s.clsName = clsName; 02499 s.uMsg = uMsg; 02500 s.wParam = wParam; 02501 s.lParam = lParam; 02502 EnumWindows(WDML_BroadcastEnumProc, (LPARAM)&s); 02503 } Generated on Sun May 27 2012 04:38:42 for ReactOS by
1.7.6.1
|