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

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

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