Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenddeclient.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 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 00028 #include <wine/debug.h> 00029 00030 WINE_DEFAULT_DEBUG_CHANNEL(ddeml); 00031 00032 static LRESULT CALLBACK WDML_ClientProc(HWND, UINT, WPARAM, LPARAM); /* only for one client, not conv list */ 00033 const char WDML_szClientConvClassA[] = "DdeClientAnsi"; 00034 const WCHAR WDML_szClientConvClassW[] = {'D','d','e','C','l','i','e','n','t','U','n','i','c','o','d','e',0}; 00035 00036 /****************************************************************************** 00037 * DdeConnectList [USER32.@] Establishes conversation with DDE servers 00038 * 00039 * PARAMS 00040 * idInst [I] Instance identifier 00041 * hszService [I] Handle to service name string 00042 * hszTopic [I] Handle to topic name string 00043 * hConvList [I] Handle to conversation list 00044 * pCC [I] Pointer to structure with context data 00045 * 00046 * RETURNS 00047 * Success: Handle to new conversation list 00048 * Failure: 0 00049 */ 00050 HCONVLIST WINAPI DdeConnectList(DWORD idInst, HSZ hszService, HSZ hszTopic, 00051 HCONVLIST hConvList, PCONVCONTEXT pCC) 00052 { 00053 FIXME("(%d,%p,%p,%p,%p): stub\n", idInst, hszService, hszTopic, hConvList, pCC); 00054 return (HCONVLIST)1; 00055 } 00056 00057 /***************************************************************** 00058 * DdeQueryNextServer [USER32.@] 00059 */ 00060 HCONV WINAPI DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev) 00061 { 00062 FIXME("(%p,%p): stub\n", hConvList, hConvPrev); 00063 return 0; 00064 } 00065 00066 /****************************************************************************** 00067 * DdeDisconnectList [USER32.@] Destroys list and terminates conversations 00068 * 00069 * 00070 * PARAMS 00071 * hConvList [I] Handle to conversation list 00072 * 00073 * RETURNS 00074 * Success: TRUE 00075 * Failure: FALSE 00076 */ 00077 BOOL WINAPI DdeDisconnectList(HCONVLIST hConvList) 00078 { 00079 FIXME("(%p): stub\n", hConvList); 00080 return TRUE; 00081 } 00082 00083 /***************************************************************** 00084 * DdeConnect (USER32.@) 00085 */ 00086 HCONV WINAPI DdeConnect(DWORD idInst, HSZ hszService, HSZ hszTopic, 00087 PCONVCONTEXT pCC) 00088 { 00089 HWND hwndClient; 00090 WDML_INSTANCE* pInstance; 00091 WDML_CONV* pConv = NULL; 00092 ATOM aSrv = 0, aTpc = 0; 00093 00094 TRACE("(0x%x,%p,%p,%p)\n", idInst, hszService, hszTopic, pCC); 00095 00096 pInstance = WDML_GetInstance(idInst); 00097 if (!pInstance) 00098 return NULL; 00099 00100 /* make sure this conv is never created */ 00101 pConv = WDML_FindConv(pInstance, WDML_CLIENT_SIDE, hszService, hszTopic); 00102 if (pConv != NULL) 00103 { 00104 ERR("This Conv already exists: (%p)\n", pConv); 00105 return NULL; 00106 } 00107 00108 /* we need to establish a conversation with 00109 server, so create a window for it */ 00110 00111 if (pInstance->unicode) 00112 { 00113 WNDCLASSEXW wndclass; 00114 00115 wndclass.cbSize = sizeof(wndclass); 00116 wndclass.style = 0; 00117 wndclass.lpfnWndProc = WDML_ClientProc; 00118 wndclass.cbClsExtra = 0; 00119 wndclass.cbWndExtra = 2 * sizeof(ULONG_PTR); 00120 wndclass.hInstance = 0; 00121 wndclass.hIcon = 0; 00122 wndclass.hCursor = 0; 00123 wndclass.hbrBackground = 0; 00124 wndclass.lpszMenuName = NULL; 00125 wndclass.lpszClassName = WDML_szClientConvClassW; 00126 wndclass.hIconSm = 0; 00127 00128 RegisterClassExW(&wndclass); 00129 00130 hwndClient = CreateWindowW(WDML_szClientConvClassW, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0); 00131 } 00132 else 00133 { 00134 WNDCLASSEXA wndclass; 00135 00136 wndclass.cbSize = sizeof(wndclass); 00137 wndclass.style = 0; 00138 wndclass.lpfnWndProc = WDML_ClientProc; 00139 wndclass.cbClsExtra = 0; 00140 wndclass.cbWndExtra = 2 * sizeof(ULONG_PTR); 00141 wndclass.hInstance = 0; 00142 wndclass.hIcon = 0; 00143 wndclass.hCursor = 0; 00144 wndclass.hbrBackground = 0; 00145 wndclass.lpszMenuName = NULL; 00146 wndclass.lpszClassName = WDML_szClientConvClassA; 00147 wndclass.hIconSm = 0; 00148 00149 RegisterClassExA(&wndclass); 00150 00151 hwndClient = CreateWindowA(WDML_szClientConvClassA, NULL, WS_POPUP, 0, 0, 0, 0, 0, 0, 0, 0); 00152 } 00153 00154 SetWindowLongPtrW(hwndClient, GWL_WDML_INSTANCE, (ULONG_PTR)pInstance); 00155 00156 if (hszService) 00157 { 00158 aSrv = WDML_MakeAtomFromHsz(hszService); 00159 if (!aSrv) goto theEnd; 00160 } 00161 if (hszTopic) 00162 { 00163 aTpc = WDML_MakeAtomFromHsz(hszTopic); 00164 if (!aTpc) goto theEnd; 00165 } 00166 00167 /* note: sent messages shall not use packing */ 00168 SendMessageTimeoutW( HWND_BROADCAST, WM_DDE_INITIATE, (WPARAM)hwndClient, MAKELPARAM(aSrv, aTpc), 00169 SMTO_ABORTIFHUNG, 2000, NULL ); 00170 00171 pInstance = WDML_GetInstance(idInst); 00172 if (!pInstance) 00173 { 00174 goto theEnd; 00175 } 00176 00177 /* At this point, Client WM_DDE_ACK should have saved hwndServer 00178 for this instance id and hwndClient if server responds. 00179 So get HCONV and return it. And add it to conv list */ 00180 pConv = WDML_GetConvFromWnd(hwndClient); 00181 if (pConv == NULL || pConv->hwndServer == 0) 00182 { 00183 WARN("Done with INITIATE, but no Server window available\n"); 00184 pConv = NULL; 00185 pInstance->lastError = DMLERR_NO_CONV_ESTABLISHED; 00186 goto theEnd; 00187 } 00188 TRACE("Connected to Server window (%p)\n", pConv->hwndServer); 00189 pConv->wConvst = XST_CONNECTED; 00190 00191 /* finish init of pConv */ 00192 if (pCC != NULL) 00193 { 00194 pConv->convContext = *pCC; 00195 } 00196 else 00197 { 00198 memset(&pConv->convContext, 0, sizeof(pConv->convContext)); 00199 pConv->convContext.cb = sizeof(pConv->convContext); 00200 pConv->convContext.iCodePage = (pInstance->unicode) ? CP_WINUNICODE : CP_WINANSI; 00201 } 00202 00203 theEnd: 00204 00205 if (aSrv) GlobalDeleteAtom(aSrv); 00206 if (aTpc) GlobalDeleteAtom(aTpc); 00207 return (HCONV)pConv; 00208 } 00209 00210 /***************************************************************** 00211 * DdeReconnect (DDEML.37) 00212 * DdeReconnect (USER32.@) 00213 */ 00214 HCONV WINAPI DdeReconnect(HCONV hConv) 00215 { 00216 WDML_CONV* pConv; 00217 WDML_CONV* pNewConv = NULL; 00218 ATOM aSrv = 0, aTpc = 0; 00219 00220 TRACE("(%p)\n", hConv); 00221 00222 pConv = WDML_GetConv(hConv, FALSE); 00223 if (pConv != NULL && (pConv->wStatus & ST_CLIENT)) 00224 { 00225 BOOL ret; 00226 00227 /* to reestablish a connection, we have to make sure that: 00228 * 1/ pConv is the conversation attached to the client window (it wouldn't be 00229 * if a call to DdeReconnect would have already been done...) 00230 * FIXME: is this really an error ??? 00231 * 2/ the pConv conversation had really been deconnected 00232 */ 00233 if (pConv == WDML_GetConvFromWnd(pConv->hwndClient) && 00234 (pConv->wStatus & ST_TERMINATED) && !(pConv->wStatus & ST_CONNECTED)) 00235 { 00236 HWND hwndClient = pConv->hwndClient; 00237 HWND hwndServer = pConv->hwndServer; 00238 00239 SetWindowLongPtrW(pConv->hwndClient, GWL_WDML_CONVERSATION, 0); 00240 00241 aSrv = WDML_MakeAtomFromHsz(pConv->hszService); 00242 aTpc = WDML_MakeAtomFromHsz(pConv->hszTopic); 00243 if (!aSrv || !aTpc) goto theEnd; 00244 00245 /* note: sent messages shall not use packing */ 00246 ret = SendMessageW(hwndServer, WM_DDE_INITIATE, (WPARAM)hwndClient, 00247 MAKELPARAM(aSrv, aTpc)); 00248 00249 pConv = WDML_GetConv(hConv, FALSE); 00250 if (pConv == NULL) 00251 { 00252 FIXME("Should fail reconnection\n"); 00253 goto theEnd; 00254 } 00255 00256 if (ret && (pNewConv = WDML_GetConvFromWnd(pConv->hwndClient)) != NULL) 00257 { 00258 /* re-establish all links... */ 00259 WDML_LINK* pLink; 00260 00261 for (pLink = pConv->instance->links[WDML_CLIENT_SIDE]; pLink; pLink = pLink->next) 00262 { 00263 if (pLink->hConv == hConv) 00264 { 00265 /* try to reestablish the links... */ 00266 DdeClientTransaction(NULL, 0, (HCONV)pNewConv, pLink->hszItem, pLink->uFmt, 00267 pLink->transactionType, 1000, NULL); 00268 } 00269 } 00270 } 00271 else 00272 { 00273 /* reset the conversation as it was */ 00274 SetWindowLongPtrW(pConv->hwndClient, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv); 00275 } 00276 } 00277 } 00278 00279 theEnd: 00280 00281 if (aSrv) GlobalDeleteAtom(aSrv); 00282 if (aTpc) GlobalDeleteAtom(aTpc); 00283 return (HCONV)pNewConv; 00284 } 00285 00286 /****************************************************************** 00287 * WDML_ClientQueueAdvise 00288 * 00289 * Creates and queue an WM_DDE_ADVISE transaction 00290 */ 00291 static WDML_XACT* WDML_ClientQueueAdvise(WDML_CONV* pConv, UINT wType, UINT wFmt, HSZ hszItem) 00292 { 00293 DDEADVISE* pDdeAdvise; 00294 WDML_XACT* pXAct; 00295 ATOM atom; 00296 00297 TRACE("XTYP_ADVSTART (with%s data) transaction\n", (wType & XTYPF_NODATA) ? "out" : ""); 00298 00299 atom = WDML_MakeAtomFromHsz(hszItem); 00300 if (!atom) return NULL; 00301 00302 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_ADVISE, wFmt, hszItem); 00303 if (!pXAct) 00304 { 00305 GlobalDeleteAtom(atom); 00306 return NULL; 00307 } 00308 00309 pXAct->wType = wType & ~0x0F; 00310 pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, sizeof(DDEADVISE)); 00311 /* FIXME: hMem is unfreed for now... should be deleted in server */ 00312 00313 /* pack DdeAdvise */ 00314 pDdeAdvise = GlobalLock(pXAct->hMem); 00315 pDdeAdvise->fAckReq = (wType & XTYPF_ACKREQ) ? TRUE : FALSE; 00316 pDdeAdvise->fDeferUpd = (wType & XTYPF_NODATA) ? TRUE : FALSE; 00317 pDdeAdvise->cfFormat = wFmt; 00318 GlobalUnlock(pXAct->hMem); 00319 00320 pXAct->lParam = PackDDElParam(WM_DDE_ADVISE, (UINT_PTR)pXAct->hMem, atom); 00321 00322 return pXAct; 00323 } 00324 00325 /****************************************************************** 00326 * WDML_HandleAdviseReply 00327 * 00328 * handles the reply to an advise request 00329 */ 00330 static WDML_QUEUE_STATE WDML_HandleAdviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) 00331 { 00332 DDEACK ddeAck; 00333 UINT_PTR uiLo, uiHi; 00334 HSZ hsz; 00335 00336 if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) 00337 { 00338 return WDML_QS_PASS; 00339 } 00340 00341 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 00342 hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); 00343 00344 if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) 00345 return WDML_QS_PASS; 00346 00347 GlobalDeleteAtom(uiHi); 00348 FreeDDElParam(WM_DDE_ACK, msg->lParam); 00349 00350 if (ack) *ack = uiLo; 00351 WDML_ExtractAck(uiLo, &ddeAck); 00352 00353 if (ddeAck.fAck) 00354 { 00355 WDML_LINK* pLink; 00356 00357 /* billx: first to see if the link is already created. */ 00358 pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, 00359 pXAct->hszItem, TRUE, pXAct->wFmt); 00360 if (pLink != NULL) 00361 { 00362 /* we found a link, and only need to modify it in case it changes */ 00363 pLink->transactionType = pXAct->wType; 00364 } 00365 else 00366 { 00367 WDML_AddLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, 00368 pXAct->wType, pXAct->hszItem, pXAct->wFmt); 00369 } 00370 pXAct->hDdeData = (HDDEDATA)1; 00371 } 00372 else 00373 { 00374 TRACE("Returning FALSE on XTYP_ADVSTART - fAck was FALSE\n"); 00375 GlobalFree(pXAct->hMem); 00376 pXAct->hDdeData = NULL; 00377 } 00378 00379 return WDML_QS_HANDLED; 00380 } 00381 00382 /****************************************************************** 00383 * WDML_ClientQueueUnadvise 00384 * 00385 * queues an unadvise transaction 00386 */ 00387 static WDML_XACT* WDML_ClientQueueUnadvise(WDML_CONV* pConv, UINT wFmt, HSZ hszItem) 00388 { 00389 WDML_XACT* pXAct; 00390 ATOM atom; 00391 00392 TRACE("XTYP_ADVSTOP transaction\n"); 00393 00394 atom = WDML_MakeAtomFromHsz(hszItem); 00395 if (!atom) return NULL; 00396 00397 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_UNADVISE, wFmt, hszItem); 00398 if (!pXAct) 00399 { 00400 GlobalDeleteAtom(atom); 00401 return NULL; 00402 } 00403 00404 /* end advise loop: post WM_DDE_UNADVISE to server to terminate link 00405 * on the specified item. 00406 */ 00407 pXAct->lParam = PackDDElParam(WM_DDE_UNADVISE, wFmt, atom); 00408 return pXAct; 00409 } 00410 00411 /****************************************************************** 00412 * WDML_HandleUnadviseReply 00413 * 00414 * 00415 */ 00416 static WDML_QUEUE_STATE WDML_HandleUnadviseReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) 00417 { 00418 DDEACK ddeAck; 00419 UINT_PTR uiLo, uiHi; 00420 HSZ hsz; 00421 00422 if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) 00423 { 00424 return WDML_QS_PASS; 00425 } 00426 00427 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 00428 hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); 00429 00430 if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) 00431 return WDML_QS_PASS; 00432 00433 FreeDDElParam(WM_DDE_ACK, msg->lParam); 00434 GlobalDeleteAtom(uiHi); 00435 00436 if (ack) *ack = uiLo; 00437 WDML_ExtractAck(uiLo, &ddeAck); 00438 00439 TRACE("WM_DDE_ACK received while waiting for a timeout\n"); 00440 00441 if (!ddeAck.fAck) 00442 { 00443 TRACE("Returning FALSE on XTYP_ADVSTOP - fAck was FALSE\n"); 00444 pXAct->hDdeData = NULL; 00445 } 00446 else 00447 { 00448 /* billx: remove the link */ 00449 WDML_RemoveLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, 00450 pXAct->hszItem, pXAct->wFmt); 00451 pXAct->hDdeData = (HDDEDATA)1; 00452 } 00453 return WDML_QS_HANDLED; 00454 } 00455 00456 /****************************************************************** 00457 * WDML_ClientQueueRequest 00458 * 00459 * 00460 */ 00461 static WDML_XACT* WDML_ClientQueueRequest(WDML_CONV* pConv, UINT wFmt, HSZ hszItem) 00462 { 00463 WDML_XACT* pXAct; 00464 ATOM atom; 00465 00466 TRACE("XTYP_REQUEST transaction\n"); 00467 00468 atom = WDML_MakeAtomFromHsz(hszItem); 00469 if (!atom) return NULL; 00470 00471 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_REQUEST, wFmt, hszItem); 00472 if (!pXAct) 00473 { 00474 GlobalDeleteAtom(atom); 00475 return NULL; 00476 } 00477 00478 pXAct->lParam = PackDDElParam(WM_DDE_REQUEST, wFmt, atom); 00479 00480 return pXAct; 00481 } 00482 00483 /****************************************************************** 00484 * WDML_HandleRequestReply 00485 * 00486 * 00487 */ 00488 static WDML_QUEUE_STATE WDML_HandleRequestReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) 00489 { 00490 DDEACK ddeAck; 00491 WINE_DDEHEAD wdh; 00492 UINT_PTR uiLo, uiHi; 00493 HSZ hsz; 00494 00495 if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) 00496 return WDML_QS_PASS; 00497 00498 switch (msg->message) 00499 { 00500 case WM_DDE_ACK: 00501 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 00502 FreeDDElParam(WM_DDE_ACK, msg->lParam); 00503 GlobalDeleteAtom(uiHi); 00504 if (ack) *ack = uiLo; 00505 WDML_ExtractAck(uiLo, &ddeAck); 00506 pXAct->hDdeData = 0; 00507 if (ddeAck.fAck) 00508 ERR("Positive answer should appear in NACK for a request, assuming negative\n"); 00509 TRACE("Negative answer...\n"); 00510 break; 00511 00512 case WM_DDE_DATA: 00513 UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi); 00514 TRACE("Got the result (%08lx)\n", uiLo); 00515 00516 hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); 00517 00518 if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) 00519 return WDML_QS_PASS; 00520 00521 pXAct->hDdeData = WDML_Global2DataHandle(pConv, (HGLOBAL)uiLo, &wdh); 00522 if (wdh.fRelease) 00523 { 00524 GlobalFree((HGLOBAL)uiLo); 00525 } 00526 if (wdh.fAckReq) 00527 { 00528 pConv->instance->lastError = DMLERR_MEMORY_ERROR; 00529 } 00530 else 00531 { 00532 GlobalDeleteAtom(uiHi); 00533 FreeDDElParam(WM_DDE_ACK, msg->lParam); 00534 } 00535 break; 00536 00537 default: 00538 FreeDDElParam(msg->message, msg->lParam); 00539 return WDML_QS_PASS; 00540 } 00541 00542 return WDML_QS_HANDLED; 00543 } 00544 00545 /****************************************************************** 00546 * WDML_BuildExecuteCommand 00547 * 00548 * Creates a DDE block suitable for sending in WM_DDE_COMMAND 00549 * It also takes care of string conversion between the two window procedures 00550 */ 00551 static HGLOBAL WDML_BuildExecuteCommand(WDML_CONV* pConv, LPCVOID pData, DWORD cbData) 00552 { 00553 HGLOBAL hMem; 00554 BOOL clientUnicode, serverUnicode; 00555 DWORD memSize; 00556 00557 clientUnicode = pConv->instance->unicode; 00558 TRACE("client %p uses unicode = %d\n", pConv->hwndClient, clientUnicode); 00559 /* FIXME: how exactly Windows determines what to use for the server side? */ 00560 serverUnicode = IsWindowUnicode(pConv->hwndServer) && IsWindowUnicode(pConv->hwndClient); 00561 TRACE("server %p uses unicode = %d\n", pConv->hwndServer, serverUnicode); 00562 00563 if (clientUnicode == serverUnicode) 00564 { 00565 memSize = cbData; 00566 } 00567 else 00568 { 00569 if (clientUnicode) 00570 { 00571 memSize = WideCharToMultiByte( CP_ACP, 0, pData, cbData / sizeof(WCHAR), NULL, 0, NULL, NULL); 00572 } 00573 else 00574 { 00575 memSize = MultiByteToWideChar( CP_ACP, 0, pData, cbData, NULL, 0) * sizeof(WCHAR); 00576 } 00577 } 00578 00579 hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, memSize); 00580 00581 if (hMem) 00582 { 00583 LPSTR pDst; 00584 00585 pDst = GlobalLock(hMem); 00586 if (pDst) 00587 { 00588 if (clientUnicode == serverUnicode) 00589 { 00590 memcpy(pDst, pData, cbData); 00591 } 00592 else 00593 { 00594 if (clientUnicode) 00595 { 00596 WideCharToMultiByte( CP_ACP, 0, pData, cbData / sizeof(WCHAR), pDst, memSize, NULL, NULL); 00597 } 00598 else 00599 { 00600 MultiByteToWideChar( CP_ACP, 0, pData, cbData, (LPWSTR)pDst, memSize/sizeof(WCHAR)); 00601 } 00602 } 00603 00604 GlobalUnlock(hMem); 00605 } 00606 else 00607 { 00608 GlobalFree(hMem); 00609 hMem = 0; 00610 } 00611 } 00612 return hMem; 00613 } 00614 00615 /****************************************************************** 00616 * WDML_ClientQueueExecute 00617 * 00618 * 00619 */ 00620 static WDML_XACT* WDML_ClientQueueExecute(WDML_CONV* pConv, LPVOID pData, DWORD cbData) 00621 { 00622 WDML_XACT* pXAct; 00623 00624 TRACE("XTYP_EXECUTE transaction\n"); 00625 00626 if (pData == NULL) 00627 { 00628 if (cbData == (DWORD)-1) 00629 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; 00630 else 00631 pConv->instance->lastError = DMLERR_MEMORY_ERROR; 00632 return NULL; 00633 } 00634 00635 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_EXECUTE, 0, 0); 00636 if (!pXAct) 00637 return NULL; 00638 00639 if (cbData == (DWORD)-1) 00640 { 00641 HDDEDATA hDdeData = pData; 00642 00643 pData = DdeAccessData(hDdeData, &cbData); 00644 if (pData) 00645 { 00646 pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData); 00647 DdeUnaccessData(hDdeData); 00648 } 00649 } 00650 else 00651 { 00652 pXAct->hMem = WDML_BuildExecuteCommand(pConv, pData, cbData); 00653 } 00654 00655 pXAct->lParam = (LPARAM)pXAct->hMem; 00656 00657 return pXAct; 00658 } 00659 00660 /****************************************************************** 00661 * WDML_HandleExecuteReply 00662 * 00663 * 00664 */ 00665 static WDML_QUEUE_STATE WDML_HandleExecuteReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) 00666 { 00667 DDEACK ddeAck; 00668 UINT_PTR uiLo, uiHi; 00669 00670 if (msg->message != WM_DDE_ACK || WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) 00671 { 00672 return WDML_QS_PASS; 00673 } 00674 00675 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 00676 FreeDDElParam(WM_DDE_ACK, msg->lParam); 00677 00678 if ((HANDLE)uiHi != pXAct->hMem) 00679 { 00680 return WDML_QS_PASS; 00681 } 00682 00683 if (ack) *ack = uiLo; 00684 WDML_ExtractAck(uiLo, &ddeAck); 00685 pXAct->hDdeData = (HDDEDATA)(UINT_PTR)ddeAck.fAck; 00686 00687 TRACE("hDdeData = %p\n", pXAct->hDdeData); 00688 pConv->instance->lastError = (pXAct->hDdeData != 0) ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED; 00689 00690 return WDML_QS_HANDLED; 00691 } 00692 00693 /****************************************************************** 00694 * WDML_ClientQueuePoke 00695 * 00696 * 00697 */ 00698 static WDML_XACT* WDML_ClientQueuePoke(WDML_CONV* pConv, LPVOID pData, DWORD cbData, 00699 UINT wFmt, HSZ hszItem) 00700 { 00701 DDE_DATAHANDLE_HEAD *dh; 00702 WDML_XACT *pXAct; 00703 DDEPOKE *ddePoke; 00704 HGLOBAL hglobal; 00705 ATOM atom; 00706 00707 TRACE("XTYP_POKE transaction\n"); 00708 00709 atom = WDML_MakeAtomFromHsz(hszItem); 00710 if (!atom) return NULL; 00711 00712 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_POKE, wFmt, hszItem); 00713 if (!pXAct) 00714 { 00715 GlobalDeleteAtom(atom); 00716 return NULL; 00717 } 00718 00719 if (cbData == (DWORD)-1) 00720 { 00721 hglobal = pData; 00722 dh = GlobalLock(hglobal); 00723 cbData = GlobalSize(hglobal) - sizeof(DDE_DATAHANDLE_HEAD); 00724 pData = dh + 1; 00725 GlobalUnlock(hglobal); 00726 } 00727 00728 pXAct->hMem = GlobalAlloc(GHND | GMEM_DDESHARE, FIELD_OFFSET(DDEPOKE, Value[cbData])); 00729 ddePoke = GlobalLock(pXAct->hMem); 00730 if (!ddePoke) 00731 { 00732 pConv->instance->lastError = DMLERR_MEMORY_ERROR; 00733 return NULL; 00734 } 00735 00736 ddePoke->unused = 0; 00737 ddePoke->fRelease = TRUE; 00738 ddePoke->cfFormat = wFmt; 00739 memcpy(ddePoke->Value, pData, cbData); 00740 GlobalUnlock(pXAct->hMem); 00741 00742 pXAct->lParam = PackDDElParam(WM_DDE_POKE, (UINT_PTR)pXAct->hMem, atom); 00743 00744 return pXAct; 00745 } 00746 00747 /****************************************************************** 00748 * WDML_HandlePokeReply 00749 * 00750 * 00751 */ 00752 static WDML_QUEUE_STATE WDML_HandlePokeReply(WDML_CONV* pConv, MSG* msg, WDML_XACT* pXAct, DWORD *ack) 00753 { 00754 UINT_PTR uiLo, uiHi; 00755 HSZ hsz; 00756 00757 if (msg->message != WM_DDE_ACK && WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) 00758 { 00759 return WDML_QS_PASS; 00760 } 00761 00762 UnpackDDElParam(WM_DDE_ACK, msg->lParam, &uiLo, &uiHi); 00763 hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); 00764 if (DdeCmpStringHandles(hsz, pXAct->hszItem) != 0) 00765 { 00766 return WDML_QS_PASS; 00767 } 00768 FreeDDElParam(WM_DDE_ACK, msg->lParam); 00769 GlobalDeleteAtom(uiHi); 00770 00771 if (ack) *ack = uiLo; 00772 GlobalFree(pXAct->hMem); 00773 00774 pXAct->hDdeData = (HDDEDATA)TRUE; 00775 return TRUE; 00776 } 00777 00778 /****************************************************************** 00779 * WDML_ClientQueueTerminate 00780 * 00781 * Creates and queue an WM_DDE_TERMINATE transaction 00782 */ 00783 static WDML_XACT* WDML_ClientQueueTerminate(WDML_CONV* pConv) 00784 { 00785 WDML_XACT* pXAct; 00786 00787 pXAct = WDML_AllocTransaction(pConv->instance, WM_DDE_TERMINATE, 0, 0); 00788 if (!pXAct) 00789 return NULL; 00790 00791 pXAct->lParam = 0; 00792 pConv->wStatus &= ~ST_CONNECTED; 00793 00794 return pXAct; 00795 } 00796 00797 /****************************************************************** 00798 * WDML_HandleTerminateReply 00799 * 00800 * handles the reply to a terminate request 00801 */ 00802 static WDML_QUEUE_STATE WDML_HandleTerminateReply(WDML_CONV* pConv, MSG* msg) 00803 { 00804 if (msg->message != WM_DDE_TERMINATE) 00805 { 00806 /* FIXME: should delete data passed here */ 00807 return WDML_QS_SWALLOWED; 00808 } 00809 00810 if (WIN_GetFullHandle((HWND)msg->wParam) != pConv->hwndServer) 00811 { 00812 FIXME("hmmm shouldn't happen\n"); 00813 return WDML_QS_PASS; 00814 } 00815 if (!(pConv->instance->CBFflags & CBF_SKIP_DISCONNECTS)) 00816 { 00817 WDML_InvokeCallback(pConv->instance, XTYP_DISCONNECT, 0, (HCONV)pConv, 00818 0, 0, 0, 0, (pConv->wStatus & ST_ISSELF) ? 1 : 0); 00819 } 00820 WDML_RemoveConv(pConv, WDML_CLIENT_SIDE); 00821 return WDML_QS_HANDLED; 00822 } 00823 00824 /****************************************************************** 00825 * WDML_HandleIncomingData 00826 * 00827 * 00828 */ 00829 static WDML_QUEUE_STATE WDML_HandleIncomingData(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd) 00830 { 00831 UINT_PTR uiLo, uiHi; 00832 HDDEDATA hDdeDataIn, hDdeDataOut; 00833 WDML_LINK* pLink; 00834 WINE_DDEHEAD wdh; 00835 HSZ hsz; 00836 00837 TRACE("WM_DDE_DATA message received in the Client Proc!\n"); 00838 /* wParam -- sending window handle */ 00839 /* lParam -- hDdeData & item HSZ */ 00840 00841 UnpackDDElParam(WM_DDE_DATA, msg->lParam, &uiLo, &uiHi); 00842 hsz = WDML_MakeHszFromAtom(pConv->instance, uiHi); 00843 00844 hDdeDataIn = WDML_Global2DataHandle(pConv, (HGLOBAL)uiLo, &wdh); 00845 00846 /* billx: 00847 * For hot link, data should be passed to its callback with 00848 * XTYP_ADVDATA and callback should return the proper status. 00849 */ 00850 pLink = WDML_FindLink(pConv->instance, (HCONV)pConv, WDML_CLIENT_SIDE, hsz, 00851 uiLo ? TRUE : FALSE, wdh.cfFormat); 00852 if (!pLink) 00853 { 00854 WDML_DecHSZ(pConv->instance, hsz); 00855 DdeFreeDataHandle(hDdeDataIn); 00856 return WDML_QS_PASS; 00857 } 00858 00859 if (hDdeDataIn != 0 && wdh.fAckReq) 00860 { 00861 WDML_PostAck(pConv, WDML_CLIENT_SIDE, 0, FALSE, TRUE, uiHi, msg->lParam, WM_DDE_DATA); 00862 if (msg->lParam) 00863 msg->lParam = 0; 00864 } 00865 else 00866 { 00867 GlobalDeleteAtom(uiHi); 00868 } 00869 00870 hDdeDataOut = WDML_InvokeCallback(pConv->instance, XTYP_ADVDATA, pLink->uFmt, pLink->hConv, 00871 pConv->hszTopic, pLink->hszItem, hDdeDataIn, 0, 0); 00872 00873 if (hDdeDataOut != (HDDEDATA)DDE_FACK || wdh.fRelease) 00874 { 00875 if (uiLo) GlobalFree((HANDLE)uiLo); 00876 } 00877 00878 DdeFreeDataHandle(hDdeDataIn); 00879 00880 WDML_DecHSZ(pConv->instance, hsz); 00881 if (msg->lParam) 00882 FreeDDElParam(WM_DDE_DATA, msg->lParam); 00883 00884 return WDML_QS_HANDLED; 00885 } 00886 00887 /****************************************************************** 00888 * WDML_HandleIncomingTerminate 00889 * 00890 * 00891 */ 00892 static WDML_QUEUE_STATE WDML_HandleIncomingTerminate(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd) 00893 { 00894 if (pConv->hwndServer != WIN_GetFullHandle((HWND)msg->wParam)) 00895 return WDML_QS_PASS; 00896 00897 pConv->wStatus |= ST_TERMINATED; 00898 if (pConv->wStatus & ST_CONNECTED) 00899 { 00900 /* don't care about result code (if server exists or not) */ 00901 PostMessageW(pConv->hwndServer, WM_DDE_TERMINATE, (WPARAM)pConv->hwndClient, 0L); 00902 pConv->wStatus &= ~ST_CONNECTED; 00903 } 00904 /* have to keep connection around to allow reconnection */ 00905 return WDML_QS_HANDLED; 00906 } 00907 00908 /****************************************************************** 00909 * WDML_HandleReply 00910 * 00911 * handles any incoming reply, and try to match to an already sent request 00912 */ 00913 static WDML_QUEUE_STATE WDML_HandleReply(WDML_CONV* pConv, MSG* msg, HDDEDATA* hdd, DWORD *ack) 00914 { 00915 WDML_XACT* pXAct = pConv->transactions; 00916 WDML_QUEUE_STATE qs; 00917 00918 if (pConv->transactions) 00919 { 00920 if (ack) *ack = DDE_FNOTPROCESSED; 00921 /* first check message against a pending transaction, if any */ 00922 switch (pXAct->ddeMsg) 00923 { 00924 case WM_DDE_ADVISE: 00925 qs = WDML_HandleAdviseReply(pConv, msg, pXAct, ack); 00926 break; 00927 case WM_DDE_UNADVISE: 00928 qs = WDML_HandleUnadviseReply(pConv, msg, pXAct, ack); 00929 break; 00930 case WM_DDE_EXECUTE: 00931 qs = WDML_HandleExecuteReply(pConv, msg, pXAct, ack); 00932 break; 00933 case WM_DDE_REQUEST: 00934 qs = WDML_HandleRequestReply(pConv, msg, pXAct, ack); 00935 break; 00936 case WM_DDE_POKE: 00937 qs = WDML_HandlePokeReply(pConv, msg, pXAct, ack); 00938 break; 00939 case WM_DDE_TERMINATE: 00940 qs = WDML_HandleTerminateReply(pConv, msg); 00941 break; 00942 default: 00943 qs = WDML_QS_ERROR; 00944 FIXME("oooch\n"); 00945 } 00946 } 00947 else 00948 { 00949 qs = WDML_QS_PASS; 00950 } 00951 00952 /* now check the results */ 00953 switch (qs) 00954 { 00955 case WDML_QS_ERROR: 00956 case WDML_QS_SWALLOWED: 00957 *hdd = 0; 00958 break; 00959 case WDML_QS_HANDLED: 00960 /* ok, we have resolved a pending transaction 00961 * notify callback if asynchronous. 00962 */ 00963 if (pXAct->dwTimeout == TIMEOUT_ASYNC && pXAct->ddeMsg != WM_DDE_TERMINATE) 00964 { 00965 WDML_InvokeCallback(pConv->instance, XTYP_XACT_COMPLETE, pXAct->wFmt, 00966 (HCONV)pConv, pConv->hszTopic, pXAct->hszItem, 00967 pXAct->hDdeData, MAKELONG(0, pXAct->xActID), 0 /* FIXME */); 00968 qs = WDML_QS_PASS; 00969 } 00970 else 00971 { 00972 *hdd = pXAct->hDdeData; 00973 } 00974 break; 00975 case WDML_QS_PASS: 00976 /* no pending transaction found, try a warm/hot link or a termination request */ 00977 switch (msg->message) 00978 { 00979 case WM_DDE_DATA: 00980 qs = WDML_HandleIncomingData(pConv, msg, hdd); 00981 break; 00982 case WM_DDE_TERMINATE: 00983 qs = WDML_HandleIncomingTerminate(pConv, msg, hdd); 00984 break; 00985 case WM_DDE_ACK: 00986 /* This happens at end of DdeClientTransaction XTYP_EXECUTE 00987 * Without this assignment, DdeClientTransaction's return value is undefined 00988 */ 00989 *hdd = (HDDEDATA)TRUE; 00990 if (ack) 00991 *ack = DDE_FACK; 00992 break; 00993 } 00994 break; 00995 case WDML_QS_BLOCK: 00996 FIXME("shouldn't be used on client side\n"); 00997 break; 00998 } 00999 01000 return qs; 01001 } 01002 01003 /****************************************************************** 01004 * WDML_SyncWaitTransactionReply 01005 * 01006 * waits until an answer for a sent request is received 01007 * time out is also handled. only used for synchronous transactions 01008 */ 01009 static HDDEDATA WDML_SyncWaitTransactionReply(HCONV hConv, DWORD dwTimeout, const WDML_XACT* pXAct, DWORD *ack) 01010 { 01011 DWORD dwTime; 01012 DWORD err; 01013 WDML_CONV* pConv; 01014 01015 TRACE("Starting wait for a timeout of %d ms\n", dwTimeout); 01016 01017 /* FIXME: time 32 bit wrap around */ 01018 dwTimeout += GetCurrentTime(); 01019 01020 while ((dwTime = GetCurrentTime()) < dwTimeout) 01021 { 01022 /* we cannot be in the crit sect all the time because when client and server run in a 01023 * single process they need to share the access to the internal data 01024 */ 01025 if (MsgWaitForMultipleObjects(0, NULL, FALSE, 01026 dwTimeout - dwTime, QS_POSTMESSAGE) == WAIT_OBJECT_0) 01027 { 01028 MSG msg; 01029 01030 while (PeekMessageW(&msg, 0, WM_DDE_FIRST, WM_DDE_LAST, PM_REMOVE)) 01031 { 01032 HDDEDATA hdd = NULL; 01033 01034 pConv = WDML_GetConv(hConv, FALSE); 01035 if (pConv == NULL) 01036 { 01037 /* conversation no longer available... return failure */ 01038 return 0; 01039 } 01040 if (msg.hwnd == pConv->hwndClient) 01041 { 01042 /* check that either pXAct has been processed or no more xActions are pending */ 01043 BOOL ret = (pConv->transactions == pXAct); 01044 if (WDML_HandleReply(pConv, &msg, &hdd, ack) == WDML_QS_HANDLED) 01045 { 01046 TRACE("WDML_HandleReply returned WDML_QS_HANDLED\n"); 01047 ret = TRUE; 01048 } 01049 else 01050 ret = (pConv->transactions == NULL || ret); 01051 01052 if (ret) 01053 { 01054 pConv->instance->lastError = hdd ? DMLERR_NO_ERROR : DMLERR_NOTPROCESSED; 01055 return hdd; 01056 } 01057 } 01058 else 01059 { 01060 DispatchMessageW(&msg); 01061 } 01062 } 01063 } 01064 } 01065 01066 TRACE("Timeout !!\n"); 01067 01068 pConv = WDML_GetConv(hConv, FALSE); 01069 if (pConv != NULL) 01070 { 01071 if (pConv->transactions) 01072 { 01073 switch (pConv->transactions->ddeMsg) 01074 { 01075 case WM_DDE_ADVISE: err = DMLERR_ADVACKTIMEOUT; break; 01076 case WM_DDE_REQUEST: err = DMLERR_DATAACKTIMEOUT; break; 01077 case WM_DDE_EXECUTE: err = DMLERR_EXECACKTIMEOUT; break; 01078 case WM_DDE_POKE: err = DMLERR_POKEACKTIMEOUT; break; 01079 case WM_DDE_UNADVISE: err = DMLERR_UNADVACKTIMEOUT; break; 01080 default: err = DMLERR_INVALIDPARAMETER; break; 01081 } 01082 01083 pConv->instance->lastError = err; 01084 } 01085 } 01086 01087 return 0; 01088 } 01089 01090 01091 /***************************************************************** 01092 * WDML_ClientHandle 01093 */ 01094 HDDEDATA WDML_ClientHandle(WDML_CONV *pConv, WDML_XACT *pXAct, DWORD dwTimeout, LPDWORD pdwResult) 01095 { 01096 HDDEDATA hDdeData; 01097 01098 if (!PostMessageW(pConv->hwndServer, pXAct->ddeMsg, (WPARAM)pConv->hwndClient, pXAct->lParam)) 01099 { 01100 WARN("Failed posting message %x to %p (error=0x%x)\n", 01101 pXAct->ddeMsg, pConv->hwndServer, GetLastError()); 01102 pConv->wStatus &= ~ST_CONNECTED; 01103 pConv->instance->lastError = DMLERR_POSTMSG_FAILED; 01104 return 0; 01105 } 01106 pXAct->dwTimeout = dwTimeout; 01107 /* FIXME: should set the app bits on *pdwResult */ 01108 01109 if (dwTimeout == TIMEOUT_ASYNC) 01110 { 01111 if (pdwResult) 01112 *pdwResult = MAKELONG(0, pXAct->xActID); 01113 01114 hDdeData = (HDDEDATA)1; 01115 } 01116 else 01117 hDdeData = WDML_SyncWaitTransactionReply((HCONV)pConv, dwTimeout, pXAct, pdwResult); 01118 01119 return hDdeData; 01120 } 01121 01122 01123 /***************************************************************** 01124 * DdeClientTransaction (USER32.@) 01125 */ 01126 HDDEDATA WINAPI DdeClientTransaction(LPBYTE pData, DWORD cbData, HCONV hConv, HSZ hszItem, UINT wFmt, 01127 UINT wType, DWORD dwTimeout, LPDWORD pdwResult) 01128 { 01129 WDML_CONV* pConv; 01130 WDML_XACT* pXAct; 01131 HDDEDATA hDdeData = 0; 01132 01133 TRACE("(%p,%d,%p,%p,%x,%x,%d,%p)\n", 01134 pData, cbData, hConv, hszItem, wFmt, wType, dwTimeout, pdwResult); 01135 01136 if (hConv == 0) 01137 { 01138 WARN("Invalid conversation handle NULL\n"); 01139 return 0; 01140 } 01141 01142 pConv = WDML_GetConv(hConv, TRUE); 01143 if (pConv == NULL) 01144 { 01145 /* cannot set error... cannot get back to DDE instance */ 01146 return 0; 01147 } 01148 01149 switch (wType) 01150 { 01151 case XTYP_EXECUTE: 01152 /* Windows simply ignores hszItem and wFmt in this case */ 01153 pXAct = WDML_ClientQueueExecute(pConv, pData, cbData); 01154 if (pXAct == NULL) 01155 return 0; 01156 break; 01157 case XTYP_POKE: 01158 if (!hszItem) 01159 { 01160 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; 01161 return 0; 01162 } 01163 pXAct = WDML_ClientQueuePoke(pConv, pData, cbData, wFmt, hszItem); 01164 break; 01165 case XTYP_ADVSTART|XTYPF_NODATA: 01166 case XTYP_ADVSTART|XTYPF_NODATA|XTYPF_ACKREQ: 01167 case XTYP_ADVSTART: 01168 case XTYP_ADVSTART|XTYPF_ACKREQ: 01169 if (pData) 01170 { 01171 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; 01172 return 0; 01173 } 01174 pXAct = WDML_ClientQueueAdvise(pConv, wType, wFmt, hszItem); 01175 break; 01176 case XTYP_ADVSTOP: 01177 if (pData) 01178 { 01179 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; 01180 return 0; 01181 } 01182 pXAct = WDML_ClientQueueUnadvise(pConv, wFmt, hszItem); 01183 break; 01184 case XTYP_REQUEST: 01185 if (pData || !hszItem) 01186 { 01187 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; 01188 return 0; 01189 } 01190 pXAct = WDML_ClientQueueRequest(pConv, wFmt, hszItem); 01191 break; 01192 default: 01193 FIXME("Unknown transaction type %04x\n", wType); 01194 /* unknown transaction type */ 01195 pConv->instance->lastError = DMLERR_INVALIDPARAMETER; 01196 return 0; 01197 } 01198 01199 if (pXAct == NULL) 01200 { 01201 pConv->instance->lastError = DMLERR_MEMORY_ERROR; 01202 return 0; 01203 } 01204 01205 WDML_QueueTransaction(pConv, pXAct); 01206 01207 TRACE("pConv->wStatus %04x\n", pConv->wStatus); 01208 01209 if (pConv->wStatus & ST_BLOCKED) 01210 { 01211 TRACE("Transactions are blocked, add to the queue and exit\n"); 01212 return (HDDEDATA)1; 01213 } 01214 01215 hDdeData = WDML_ClientHandle(pConv, pXAct, dwTimeout, pdwResult); 01216 if (dwTimeout != TIMEOUT_ASYNC) 01217 { 01218 WDML_UnQueueTransaction(pConv, pXAct); 01219 WDML_FreeTransaction(pConv->instance, pXAct, TRUE); 01220 } 01221 01222 return hDdeData; 01223 } 01224 01225 /***************************************************************** 01226 * DdeAbandonTransaction (USER32.@) 01227 */ 01228 BOOL WINAPI DdeAbandonTransaction(DWORD idInst, HCONV hConv, DWORD idTransaction) 01229 { 01230 WDML_INSTANCE* pInstance; 01231 WDML_CONV* pConv; 01232 WDML_XACT* pXAct; 01233 01234 if ((pInstance = WDML_GetInstance(idInst))) 01235 { 01236 if (hConv) 01237 { 01238 if ((pConv = WDML_GetConv(hConv, TRUE)) && pConv->instance == pInstance) 01239 { 01240 for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next) 01241 { 01242 if (pXAct->dwTimeout == TIMEOUT_ASYNC && 01243 (idTransaction == 0 || pXAct->xActID == idTransaction)) 01244 { 01245 WDML_UnQueueTransaction(pConv, pXAct); 01246 WDML_FreeTransaction(pInstance, pXAct, TRUE); 01247 } 01248 } 01249 } 01250 } 01251 else 01252 { 01253 for (pConv = pInstance->convs[WDML_CLIENT_SIDE]; pConv; pConv = pConv->next) 01254 { 01255 if (!(pConv->wStatus & ST_CONNECTED)) continue; 01256 for (pXAct = pConv->transactions; pXAct; pXAct = pXAct->next) 01257 { 01258 if (pXAct->dwTimeout == TIMEOUT_ASYNC) 01259 { 01260 WDML_UnQueueTransaction(pConv, pXAct); 01261 WDML_FreeTransaction(pInstance, pXAct, TRUE); 01262 } 01263 } 01264 } 01265 } 01266 } 01267 01268 return TRUE; 01269 } 01270 01271 /****************************************************************** 01272 * WDML_ClientProc 01273 * 01274 * Window Proc created on client side for each conversation 01275 */ 01276 static LRESULT CALLBACK WDML_ClientProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) 01277 { 01278 UINT uiLo, uiHi; 01279 WDML_CONV* pConv = NULL; 01280 HSZ hszSrv, hszTpc; 01281 01282 TRACE("%p %04x %08lx %08lx\n", hwnd, iMsg, wParam , lParam); 01283 01284 if (iMsg == WM_DDE_ACK && 01285 /* in the initial WM_INITIATE sendmessage */ 01286 ((pConv = WDML_GetConvFromWnd(hwnd)) == NULL || pConv->wStatus == XST_INIT1)) 01287 { 01288 /* In response to WM_DDE_INITIATE, save server window */ 01289 char buf[256]; 01290 WDML_INSTANCE* pInstance; 01291 01292 /* note: sent messages do not need packing */ 01293 uiLo = LOWORD(lParam); 01294 uiHi = HIWORD(lParam); 01295 01296 /* FIXME: convlist should be handled here */ 01297 if (pConv) 01298 { 01299 /* we already have started the conv with a server, drop other replies */ 01300 GlobalDeleteAtom(uiLo); 01301 GlobalDeleteAtom(uiHi); 01302 PostMessageW((HWND)wParam, WM_DDE_TERMINATE, (WPARAM)hwnd, 0); 01303 return 0; 01304 } 01305 01306 pInstance = WDML_GetInstanceFromWnd(hwnd); 01307 01308 hszSrv = WDML_MakeHszFromAtom(pInstance, uiLo); 01309 hszTpc = WDML_MakeHszFromAtom(pInstance, uiHi); 01310 01311 pConv = WDML_AddConv(pInstance, WDML_CLIENT_SIDE, hszSrv, hszTpc, hwnd, (HWND)wParam); 01312 01313 SetWindowLongPtrW(hwnd, GWL_WDML_CONVERSATION, (ULONG_PTR)pConv); 01314 pConv->wStatus |= ST_CONNECTED; 01315 pConv->wConvst = XST_INIT1; 01316 01317 /* check if server is handled by DDEML */ 01318 if ((GetClassNameA((HWND)wParam, buf, sizeof(buf)) && 01319 lstrcmpiA(buf, WDML_szServerConvClassA) == 0) || 01320 (GetClassNameW((HWND)wParam, (LPWSTR)buf, sizeof(buf)/sizeof(WCHAR)) && 01321 lstrcmpiW((LPWSTR)buf, WDML_szServerConvClassW) == 0)) 01322 { 01323 pConv->wStatus |= ST_ISLOCAL; 01324 } 01325 01326 GlobalDeleteAtom(uiLo); 01327 GlobalDeleteAtom(uiHi); 01328 01329 /* accept conversation */ 01330 return 1; 01331 } 01332 01333 if (iMsg >= WM_DDE_FIRST && iMsg <= WM_DDE_LAST) 01334 { 01335 pConv = WDML_GetConvFromWnd(hwnd); 01336 01337 if (pConv) 01338 { 01339 MSG msg; 01340 HDDEDATA hdd; 01341 01342 msg.hwnd = hwnd; 01343 msg.message = iMsg; 01344 msg.wParam = wParam; 01345 msg.lParam = lParam; 01346 01347 WDML_HandleReply(pConv, &msg, &hdd, NULL); 01348 } 01349 01350 return 0; 01351 } 01352 01353 return IsWindowUnicode(hwnd) ? DefWindowProcW(hwnd, iMsg, wParam, lParam) : 01354 DefWindowProcA(hwnd, iMsg, wParam, lParam); 01355 } 01356 01357 /***************************************************************** 01358 * DdeDisconnect (USER32.@) 01359 */ 01360 BOOL WINAPI DdeDisconnect(HCONV hConv) 01361 { 01362 WDML_CONV* pConv = NULL; 01363 WDML_XACT* pXAct; 01364 BOOL ret = FALSE; 01365 01366 TRACE("(%p)\n", hConv); 01367 01368 if (hConv == 0) 01369 { 01370 WARN("DdeDisconnect(): hConv = 0\n"); 01371 return FALSE; 01372 } 01373 01374 pConv = WDML_GetConv(hConv, TRUE); 01375 if (pConv != NULL) 01376 { 01377 if (pConv->wStatus & ST_CLIENT) 01378 { 01379 /* FIXME: should abandon all pending transactions */ 01380 pXAct = WDML_ClientQueueTerminate(pConv); 01381 if (pXAct != NULL) 01382 { 01383 if (PostMessageW(pConv->hwndServer, pXAct->ddeMsg, 01384 (WPARAM)pConv->hwndClient, pXAct->lParam)) 01385 { 01386 WDML_SyncWaitTransactionReply(hConv, 10000, pXAct, NULL); 01387 ret = TRUE; 01388 } 01389 else 01390 pConv->instance->lastError = DMLERR_POSTMSG_FAILED; 01391 01392 WDML_FreeTransaction(pConv->instance, pXAct, TRUE); 01393 /* still have to destroy data associated with conversation */ 01394 WDML_RemoveConv(pConv, WDML_CLIENT_SIDE); 01395 } 01396 else 01397 { 01398 FIXME("Not implemented yet for a server side conversation\n"); 01399 } 01400 } 01401 } 01402 01403 return ret; 01404 } 01405 01406 /***************************************************************** 01407 * DdeImpersonateClient (USER32.@) 01408 */ 01409 BOOL WINAPI DdeImpersonateClient(HCONV hConv) 01410 { 01411 WDML_CONV* pConv; 01412 BOOL ret = FALSE; 01413 01414 TRACE("(%p)\n", hConv); 01415 01416 pConv = WDML_GetConv(hConv, TRUE); 01417 if (pConv) 01418 { 01419 ret = ImpersonateDdeClientWindow(pConv->hwndClient, pConv->hwndServer); 01420 } 01421 return ret; 01422 } Generated on Fri May 25 2012 04:37:08 for ReactOS by
1.7.6.1
|