ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ddeclient.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.