Fixed the displaying of the FOURCC codes in _dump_pixelformat.
[wine] / dlls / user / ddeml.c
1 /*
2  * DDEML library
3  *
4  * Copyright 1997 Alexandre Julliard
5  * Copyright 1997 Len White
6  * Copyright 1999 Keith Matthews
7  */
8
9 /* Only empty stubs for now */
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include "winbase.h"
14 #include "windef.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17 #include "ddeml.h"
18 #include "winerror.h"
19 #include "heap.h"
20 #include "debugtools.h"
21 #include "winnt.h"
22
23 DEFAULT_DEBUG_CHANNEL(ddeml);
24
25 /* Has defined in atom.c file.
26  */
27 #define MAX_ATOM_LEN              255
28
29 /* Maximum buffer size ( including the '\0' ).
30  */
31 #define MAX_BUFFER_LEN            (MAX_ATOM_LEN + 1)
32
33 /*  typedef struct {
34         DWORD           nLength;
35         LPVOID          lpSecurityDescriptor;
36         BOOL            bInheritHandle;
37 }       SECURITY_ATTRIBUTES; */
38
39 /* This is a simple list to keep track of the strings created
40  * by DdeCreateStringHandle.  The list is used to free
41  * the strings whenever DdeUninitialize is called.
42  * This mechanism is not complete and does not handle multiple instances.
43  * Most of the DDE API use a DWORD parameter indicating which instance
44  * of a given program is calling them.  The API are supposed to
45  * associate the data to the instance that created it.
46  */
47 typedef struct tagHSZNode HSZNode;
48 struct tagHSZNode
49 {
50     HSZNode* next;
51     HSZ hsz;
52 };
53
54
55 typedef struct tagServiceNode ServiceNode;
56 struct tagServiceNode
57 {
58     ServiceNode* next;
59     HSZ hsz;
60     BOOL16              FilterOn;
61 };
62 typedef struct DDE_HANDLE_ENTRY {
63     BOOL16              Monitor;        /* have these two as full Booleans cos they'll be tested frequently */
64     BOOL16              Client_only;    /* bit wasteful of space but it will be faster */
65     BOOL16              Unicode;        /* Flag to indicate Win32 API used to initialise */
66     BOOL16              Win16;          /* flag to indicate Win16 API used to initialize */
67     DWORD               Instance_id;  /* needed to track monitor usage */
68     struct DDE_HANDLE_ENTRY    *Next_Entry;
69     HSZNode     *Node_list;
70     PFNCALLBACK         CallBack;
71     DWORD               CBF_Flags;
72     DWORD               Monitor_flags;
73     UINT              Txn_count;      /* count transactions open to simplify closure */
74     DWORD               Last_Error; 
75     ServiceNode*                ServiceNames;
76 } DDE_HANDLE_ENTRY;
77
78 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
79 static DWORD            DDE_Max_Assigned_Instance = 0;  /* OK for present, may have to worry about wrap-around later */
80 static const char       *DDEInstanceAccess = "DDEMaxInstance";
81 static const char       *DDEHandleAccess = "DDEHandleAccess";
82 static HANDLE           inst_count_mutex = 0;
83 static HANDLE           handle_mutex = 0;
84
85 #define TRUE    1
86 #define FALSE   0
87
88
89 /******************************************************************************
90  *            RemoveHSZNodes    (INTERNAL)
91  *
92  * Remove a node from the list of HSZ nodes.
93  *
94  ******************************************************************************
95  *
96  *      Change History
97  *
98  *  Vn       Date       Author                  Comment
99  *
100  *  1.0      Dec 1998  Corel/Macadamian    Initial version
101  *  1.1      Mar 1999  Keith Matthews      Added multiple instance handling
102  *
103  */
104 static void RemoveHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
105 {
106     HSZNode* pPrev = NULL;
107     HSZNode* pCurrent = NULL;
108
109     /* Set the current node at the start of the list.
110      */
111     pCurrent = reference_inst->Node_list;
112     /* While we have more nodes.
113      */
114     while( pCurrent != NULL )
115     {
116         /* If we found the node we were looking for.
117          */
118         if( pCurrent->hsz == hsz )
119         {
120             /* Remove the node.
121              */
122             /* If the first node in the list is to to be removed.
123              * Set the global list pointer to the next node.
124              */
125             if( pCurrent == reference_inst->Node_list )
126             {
127                 reference_inst->Node_list = pCurrent->next;
128             }
129             /* Just fix the pointers has to skip the current
130              * node so we can delete it.
131              */
132             else
133             {
134                 pPrev->next = pCurrent->next;
135             }
136             /* Destroy this node.
137              */
138             free( pCurrent );
139             break;
140         }
141         /* Save the previous node pointer.
142          */
143         pPrev = pCurrent;
144         /* Move on to the next node.
145          */
146         pCurrent = pCurrent->next;
147     }
148 }
149
150 /******************************************************************************
151  *            FreeAndRemoveHSZNodes    (INTERNAL)
152  *
153  * Frees up all the strings still allocated in the list and
154  * remove all the nodes from the list of HSZ nodes.
155  *
156  ******************************************************************************
157  *
158  *      Change History
159  *
160  *  Vn       Date       Author                  Comment
161  *
162  *  1.0      Dec 1998  Corel/Macadamian    Initial version
163  *  1.1      Mar 1999  Keith Matthews      Added multiple instance handling
164  *
165  */
166 static void FreeAndRemoveHSZNodes( DWORD idInst, DDE_HANDLE_ENTRY * reference_inst )
167 {
168     /* Free any strings created in this instance.
169      */
170     while( reference_inst->Node_list != NULL )
171     {
172         DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
173     }
174 }
175
176 /******************************************************************************
177  *            InsertHSZNode    (INTERNAL)
178  *
179  * Insert a node to the head of the list.
180  *
181  ******************************************************************************
182  *
183  *      Change History
184  *
185  *  Vn       Date       Author                  Comment
186  *
187  *  1.0      Dec 1998  Corel/Macadamian    Initial version
188  *  1.1      Mar 1999  Keith Matthews      Added instance handling
189  *  1.2      Jun 1999  Keith Matthews      Added Usage count handling
190  *
191  */
192 static void InsertHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
193 {
194     if( hsz != 0 )
195     {
196         HSZNode* pNew = NULL;
197         /* Create a new node for this HSZ.
198          */
199         pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
200         if( pNew != NULL )
201         {
202             /* Set the handle value.
203              */
204             pNew->hsz = hsz;
205             /* Attach the node to the head of the list. i.e most recently added is first
206              */
207             pNew->next = reference_inst->Node_list;
208
209             /* The new node is now at the head of the list
210              * so set the global list pointer to it.
211              */
212             reference_inst->Node_list = pNew;
213             TRACE("HSZ node list entry added\n");
214         }
215     }
216 }
217
218 /*****************************************************************************
219  *      Find_Instance_Entry
220  *
221  *      generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
222  *      for an instance Id, or NULL if the entry does not exist
223  *
224  *      ASSUMES the mutex protecting the handle entry list is reserved before calling
225  *
226  ******************************************************************************
227  *
228  *      Change History
229  *
230  *  Vn       Date       Author                  Comment
231  *
232  *  1.0      March 1999  Keith Matthews      1st implementation
233              */
234  DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
235 {
236         DDE_HANDLE_ENTRY * reference_inst;
237         reference_inst =  DDE_Handle_Table_Base;
238         while ( reference_inst != NULL )
239         {
240                 if ( reference_inst->Instance_id == InstId )
241                 {
242                         TRACE("Instance entry found\n");
243                         return reference_inst;
244         }
245                 reference_inst = reference_inst->Next_Entry;
246     }
247         TRACE("Instance entry missing\n");
248         return NULL;
249 }
250
251 /*****************************************************************************
252  *      Find_Service_Name
253  *
254  *      generic routine to return a pointer to the relevant ServiceNode
255  *      for a given service name, or NULL if the entry does not exist
256  *
257  *      ASSUMES the mutex protecting the handle entry list is reserved before calling
258  *
259  ******************************************************************************
260  *
261  *      Change History
262  *
263  *  Vn       Date       Author                  Comment
264  *
265  *  1.0      May 1999  Keith Matthews      1st implementation
266              */
267  ServiceNode *Find_Service_Name (HSZ Service_Name, DDE_HANDLE_ENTRY* this_instance)
268 {
269         ServiceNode * reference_name=  this_instance->ServiceNames;
270         while ( reference_name != NULL )
271         {
272                 if ( reference_name->hsz == Service_Name )
273                 {
274                         TRACE("Service Name found\n");
275                         return reference_name;
276         }
277                 reference_name = reference_name->next;
278     }
279         TRACE("Service name missing\n");
280         return NULL;
281 }
282
283
284 /******************************************************************************
285  *      Release_reserved_mutex
286  *
287  *      generic routine to release a reserved mutex
288  *
289  *
290  ******************************************************************************
291  *
292  *      Change History
293  *
294  *  Vn       Date       Author                  Comment
295  *
296  *  1.0      Jan 1999  Keith Matthews        Initial version
297  *  1.1      Mar 1999  Keith Matthews        Corrected Heap handling. Corrected re-initialisation handling
298  *  1.2      Aug 1999  Jürgen Schmied        Corrected error handling
299  *
300  */
301 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i , 
302     DDE_HANDLE_ENTRY *this_instance)
303 {
304         if (!ReleaseMutex(mutex))
305         {
306                 ERR("ReleaseMutex failed - %s mutex %li\n",mutex_name,GetLastError());
307                 HeapFree(GetProcessHeap(), 0, this_instance);
308                 if ( release_handle_m )
309                 {
310                         ReleaseMutex(handle_mutex);
311                 }
312                 return DMLERR_SYS_ERROR;
313          }
314         if ( release_this_i )
315         {
316                 HeapFree(GetProcessHeap(), 0, this_instance);
317         }
318         return DMLERR_NO_ERROR;
319 }
320
321 /******************************************************************************
322  *      WaitForMutex
323  *
324  *      generic routine to wait for the mutex
325  *
326  *
327  ******************************************************************************
328  *
329  *      Change History
330  *
331  *  Vn       Date       Author                  Comment
332  *
333  *  1.0      Aug 1999  Juergen Schmied       Initial version
334  *
335  */
336 static BOOL WaitForMutex (HANDLE mutex)
337 {
338         DWORD result;
339
340         result = WaitForSingleObject(mutex,1000);
341
342         /* both errors should never occur */
343         if (WAIT_TIMEOUT == result)
344         {
345                 ERR("WaitForSingleObject timed out\n");
346                 return FALSE;
347         }
348
349         if (WAIT_FAILED == result)
350         {
351                 ERR("WaitForSingleObject failed - error %li\n", GetLastError());
352                 return FALSE;
353         }
354         return TRUE;
355 }
356 /******************************************************************************
357  *              IncrementInstanceId
358  *
359  *      generic routine to increment the max instance Id and allocate a new application instance
360  *
361  ******************************************************************************
362  *
363  *      Change History
364  *
365  *  Vn       Date       Author                  Comment
366  *
367  *  1.0      Jan 1999  Keith Matthews        Initial version
368  *
369  */
370 DWORD IncrementInstanceId( DDE_HANDLE_ENTRY *this_instance)
371 {
372         SECURITY_ATTRIBUTES s_attrib;
373
374         /*  Need to set up Mutex in case it is not already present */
375         /* increment handle count & get value */
376         if ( !inst_count_mutex )
377         {
378                 s_attrib.bInheritHandle = TRUE;
379                 s_attrib.lpSecurityDescriptor = NULL;
380                 s_attrib.nLength = sizeof(s_attrib);
381                 inst_count_mutex = CreateMutexA(&s_attrib,1,DDEInstanceAccess); /* 1st time through */
382                 inst_count_mutex = ConvertToGlobalHandle(inst_count_mutex); /* fixme when having seperate adresspaces*/
383         } else {
384                 if ( !WaitForMutex(inst_count_mutex) )
385                 {
386                         return DMLERR_SYS_ERROR;
387                 }
388         }
389         if ( !inst_count_mutex )
390         {
391                 ERR("CreateMutex failed - inst_count %li\n",GetLastError());
392                 Release_reserved_mutex (handle_mutex,"handle_mutex",0,1,this_instance);
393                 return DMLERR_SYS_ERROR;
394         }
395         DDE_Max_Assigned_Instance++;
396         this_instance->Instance_id = DDE_Max_Assigned_Instance;
397         TRACE("New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
398         if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0,this_instance)) return DMLERR_SYS_ERROR;
399         return DMLERR_NO_ERROR;
400 }
401
402 /******************************************************************************
403  *              FindNotifyMonitorCallbacks
404  *
405  *      Routine to find instances that need to be notified via their callback
406  *      of some event they are monitoring
407  *
408  ******************************************************************************
409  *
410  *      Change History
411  *
412  *  Vn       Date       Author                  Comment
413  *
414  *  1.0    May 1999    Keith Matthews       Initial Version
415  *
416  */
417
418 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
419 {
420         DDE_HANDLE_ENTRY *InstanceHandle;
421         InstanceHandle = DDE_Handle_Table_Base;
422         while ( InstanceHandle != NULL )
423         {
424                 if (  (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
425                 {
426                         /*   Found an instance registered as monitor and is not ourselves
427                          *      use callback to notify where appropriate
428                          */
429                 }
430                 InstanceHandle = InstanceHandle->Next_Entry;
431         }
432 }
433
434 /******************************************************************************
435  *              DdeReserveAtom
436  *
437  *      Routine to make an extra Add on an atom to reserve it a bit longer
438  *
439  ******************************************************************************
440  *
441  *      Change History
442  *
443  *  Vn       Date       Author                  Comment
444  *
445  *  1.0    Jun 1999    Keith Matthews       Initial Version
446  *
447  */
448
449 static void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
450 {
451   if ( reference_inst->Unicode)
452   {
453         WCHAR SNameBuffer[MAX_BUFFER_LEN];
454         GlobalGetAtomNameW(hsz,SNameBuffer,MAX_BUFFER_LEN);
455         GlobalAddAtomW(SNameBuffer);
456   } else {
457         CHAR SNameBuffer[MAX_BUFFER_LEN];
458         GlobalGetAtomNameA(hsz,SNameBuffer,MAX_BUFFER_LEN);
459         GlobalAddAtomA(SNameBuffer);
460   }
461 }
462
463
464 /******************************************************************************
465  *              DdeReleaseAtom
466  *
467  *      Routine to make a delete on an atom to release it a bit sooner
468  *
469  ******************************************************************************
470  *
471  *      Change History
472  *
473  *  Vn       Date       Author                  Comment
474  *
475  *  1.0    Jun 1999    Keith Matthews       Initial Version
476  *
477  */
478
479 static void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
480 {
481     GlobalDeleteAtom( hsz );
482 }
483
484 /******************************************************************************
485  *            DdeInitialize16   (DDEML.2)
486  */
487 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
488                                DWORD afCmd, DWORD ulRes)
489 {
490     TRACE("DdeInitialize16 called - calling DdeInitializeA\n");
491     return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
492                                     afCmd, ulRes);
493 }
494
495
496 /******************************************************************************
497  *            DdeInitializeA   (USER32.106)
498  */
499 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
500                                 DWORD afCmd, DWORD ulRes )
501 {
502     TRACE("DdeInitializeA called - calling DdeInitializeW\n");
503     return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
504 }
505
506
507 /******************************************************************************
508  * DdeInitializeW [USER32.107]
509  * Registers an application with the DDEML
510  *
511  * PARAMS
512  *    pidInst     [I] Pointer to instance identifier
513  *    pfnCallback [I] Pointer to callback function
514  *    afCmd       [I] Set of command and filter flags
515  *    ulRes       [I] Reserved
516  *
517  * RETURNS
518  *    Success: DMLERR_NO_ERROR
519  *    Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
520  *
521  ******************************************************************************
522  *
523  *      Change History
524  *
525  *  Vn       Date       Author                  Comment
526  *
527  *  1.0      Pre 1998  Alexandre/Len         Initial Stub
528  *  1.1      Jan 1999  Keith Matthews        Initial (near-)complete version
529  *  1.2      Mar 1999  Keith Matthews        Corrected Heap handling, CreateMutex failure handling
530  *
531  */
532 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
533                                 DWORD afCmd, DWORD ulRes )
534 {
535
536 /*  probably not really capable of handling multiple processes, but should handle
537  *      multiple instances within one process */
538
539     SECURITY_ATTRIBUTES *s_att= NULL;
540     SECURITY_ATTRIBUTES s_attrib;
541     DWORD               err_no = 0;
542     DDE_HANDLE_ENTRY *this_instance;
543     DDE_HANDLE_ENTRY *reference_inst;
544     s_att = &s_attrib;
545
546     if( ulRes )
547     {
548         ERR("Reserved value not zero?  What does this mean?\n");
549         FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
550               afCmd,ulRes);
551         /* trap this and no more until we know more */
552         return DMLERR_NO_ERROR;
553     }
554     if (!pfnCallback ) 
555     {
556         /*  this one may be wrong - MS dll seems to accept the condition, 
557             leave this until we find out more !! */
558
559
560         /* can't set up the instance with nothing to act as a callback */
561         TRACE("No callback provided\n");
562         return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
563      }
564
565      /* grab enough heap for one control struct - not really necessary for re-initialise
566       * but allows us to use same validation routines */
567      this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( GetProcessHeap(), 0, sizeof(DDE_HANDLE_ENTRY) );
568      if ( this_instance == NULL )
569      {
570         /* catastrophe !! warn user & abort */
571         ERR("Instance create failed - out of memory\n");
572         return DMLERR_SYS_ERROR;
573      }
574      this_instance->Next_Entry = NULL;
575      this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
576
577      /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
578
579      this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
580      this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
581      this_instance->CallBack=*pfnCallback;
582      this_instance->Txn_count=0;
583      this_instance->Unicode = TRUE;
584      this_instance->Win16 = FALSE;
585      this_instance->Node_list = NULL; /* node will be added later */
586      this_instance->Monitor_flags = afCmd & MF_MASK;
587      this_instance->ServiceNames = NULL;
588
589      /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
590
591      this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
592
593      if ( ! this_instance->Client_only )
594      {
595
596         /* Check for other way of setting Client-only !! */
597
598         this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
599                         ==CBF_FAIL_ALLSVRXACTIONS;
600      }
601
602      TRACE("instance created - checking validity \n");
603
604     if( *pidInst == 0 ) {
605         /*  Initialisation of new Instance Identifier */
606         TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
607         if ( DDE_Max_Assigned_Instance == 0 )
608         {
609                 /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
610         /*  Need to set up Mutex in case it is not already present */
611         s_att->bInheritHandle = TRUE;
612         s_att->lpSecurityDescriptor = NULL;
613         s_att->nLength = sizeof(s_att);
614         handle_mutex = CreateMutexA(s_att,1,DDEHandleAccess);
615         handle_mutex = ConvertToGlobalHandle(handle_mutex); /* fixme when having seperate adresspaces*/
616         if ( !handle_mutex ) {
617                 ERR("CreateMutex failed - handle list  %li\n",GetLastError());
618                 HeapFree(GetProcessHeap(), 0, this_instance);
619                 return DMLERR_SYS_ERROR;
620         }
621     } else {
622         if ( !WaitForMutex(handle_mutex) )
623         {
624                 return DMLERR_SYS_ERROR;
625         }
626     }
627
628         TRACE("Handle Mutex created/reserved\n");
629         if (DDE_Handle_Table_Base == NULL ) 
630         {
631                 /* can't be another instance in this case, assign to the base pointer */
632                 DDE_Handle_Table_Base= this_instance;
633
634                 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
635                  *              present 
636                  *      -------------------------------      NOTE NOTE NOTE    --------------------------
637                  *              
638                  *      the manual is not clear if this condition
639                  *      applies to the first call to DdeInitialize from an application, or the 
640                  *      first call for a given callback !!!
641                 */
642
643                 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
644                 TRACE("First application instance detected OK\n");
645                 /*      allocate new instance ID */
646                 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
647
648         } else {
649                 /* really need to chain the new one in to the latest here, but after checking conditions
650                  *      such as trying to start a conversation from an application trying to monitor */
651                 reference_inst =  DDE_Handle_Table_Base;
652                 TRACE("Subsequent application instance - starting checks\n");
653                 while ( reference_inst->Next_Entry != NULL ) 
654                 {
655                         /*
656                         *       This set of tests will work if application uses same instance Id
657                         *       at application level once allocated - which is what manual implies
658                         *       should happen. If someone tries to be 
659                         *       clever (lazy ?) it will fail to pick up that later calls are for
660                         *       the same application - should we trust them ?
661                         */
662                         if ( this_instance->Instance_id == reference_inst->Instance_id) 
663                         {
664                                 /* Check 1 - must be same Client-only state */
665
666                                 if ( this_instance->Client_only != reference_inst->Client_only)
667                                 {
668                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
669                                                 return DMLERR_SYS_ERROR;
670                                         return DMLERR_DLL_USAGE;
671                                 }
672
673                                 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
674
675                                 if ( this_instance->Monitor != reference_inst->Monitor) 
676                                 {
677                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
678                                                 return DMLERR_SYS_ERROR;
679                                         return DMLERR_INVALIDPARAMETER;
680                                 }
681
682                                 /* Check 3 - must supply different callback address */
683
684                                 if ( this_instance->CallBack == reference_inst->CallBack)
685                                 {
686                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
687                                                 return DMLERR_SYS_ERROR;
688                                         return DMLERR_DLL_USAGE;
689                                 }
690                         }
691                         reference_inst = reference_inst->Next_Entry;
692                 }
693                 /*  All cleared, add to chain */
694
695                 TRACE("Application Instance checks finished\n");
696                 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
697                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0,this_instance)) return DMLERR_SYS_ERROR;
698                 reference_inst->Next_Entry = this_instance;
699         }
700         *pidInst = this_instance->Instance_id;
701         TRACE("New application instance processing finished OK\n");
702      } else {
703         /* Reinitialisation situation   --- FIX  */
704         TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
705
706         if ( !WaitForMutex(handle_mutex)  )
707         {
708                 HeapFree(GetProcessHeap(), 0, this_instance);
709                 return DMLERR_SYS_ERROR;
710         }
711
712         if (DDE_Handle_Table_Base == NULL ) 
713         {
714                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance)) return DMLERR_SYS_ERROR;
715                 return DMLERR_DLL_USAGE;
716         }
717         HeapFree(GetProcessHeap(), 0, this_instance); /* finished - release heap space used as work store */
718         /* can't reinitialise if we have initialised nothing !! */
719         reference_inst =  DDE_Handle_Table_Base;
720         /* must first check if we have been given a valid instance to re-initialise !!  how do we do that ? */
721         /*
722         *       MS allows initialisation without specifying a callback, should we allow addition of the
723         *       callback by a later call to initialise ? - if so this lot will have to change
724         */
725         while ( reference_inst->Next_Entry != NULL )
726         {
727                 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
728                 {
729                         /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
730
731                         if (  reference_inst->Client_only )
732                         {
733                            if  ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS) 
734                            {
735                                 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
736
737                                 if ( ! ( afCmd & APPCMD_CLIENTONLY))
738                                 {
739                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
740                                                 return DMLERR_SYS_ERROR;
741                                         return DMLERR_DLL_USAGE;
742                                 }
743                            }
744                         }
745                         /* Check 2 - cannot change monitor modes */
746
747                         if ( this_instance->Monitor != reference_inst->Monitor) 
748                         {
749                                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
750                                         return DMLERR_SYS_ERROR;
751                                 return DMLERR_DLL_USAGE;
752                         }
753
754                         /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
755
756                         if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
757                         {
758                                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
759                                         return DMLERR_SYS_ERROR;
760                                 return DMLERR_DLL_USAGE;
761                         }
762                         break;
763                 }
764                 reference_inst = reference_inst->Next_Entry;
765         }
766         if ( reference_inst->Next_Entry == NULL )
767         {
768                 /* Crazy situation - trying to re-initialize something that has not beeen initialized !! 
769                 *       
770                 *       Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
771                 */
772                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
773                         return DMLERR_SYS_ERROR;
774                 return DMLERR_INVALIDPARAMETER;
775         }
776         /*              All checked - change relevant flags */
777
778         reference_inst->CBF_Flags = this_instance->CBF_Flags;
779         reference_inst->Client_only = this_instance->Client_only;
780         reference_inst->Monitor_flags = this_instance->Monitor_flags;
781         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
782                 return DMLERR_SYS_ERROR;
783      }
784
785     return DMLERR_NO_ERROR;
786 }
787
788
789 /*****************************************************************
790  *            DdeUninitialize16   (DDEML.3)
791  */
792 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
793 {
794     FIXME(" stub calling DdeUninitialize\n");
795     return (BOOL16)DdeUninitialize( idInst );
796 }
797
798
799 /*****************************************************************
800  * DdeUninitialize [USER32.119]  Frees DDEML resources
801  *
802  * PARAMS
803  *    idInst [I] Instance identifier
804  *
805  * RETURNS
806  *    Success: TRUE
807  *    Failure: FALSE
808  */
809
810 BOOL WINAPI DdeUninitialize( DWORD idInst )
811 {
812         /*  Stage one - check if we have a handle for this instance
813                                                                         */
814         SECURITY_ATTRIBUTES *s_att= NULL;
815         SECURITY_ATTRIBUTES s_attrib;
816         DDE_HANDLE_ENTRY *this_instance;
817         DDE_HANDLE_ENTRY *reference_inst;
818         s_att = &s_attrib;
819
820         if ( DDE_Max_Assigned_Instance == 0 )
821         {
822                 /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
823                 return TRUE;
824         }
825
826         if ( !WaitForMutex(handle_mutex) )
827         {
828                 return DMLERR_SYS_ERROR;
829         }
830         TRACE("Handle Mutex created/reserved\n");
831         /*  First check instance 
832         */
833         this_instance = Find_Instance_Entry(idInst);
834         if ( this_instance == NULL )
835         {
836                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return FALSE;
837                 /*
838                   *     Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
839                 */
840                 return FALSE;
841         }
842         FIXME("(%ld): partial stub\n", idInst);
843
844         /*   FIXME      ++++++++++++++++++++++++++++++++++++++++++
845          *      Needs to de-register all service names
846          *      
847          */
848     /* Free the nodes that were not freed by this instance
849      * and remove the nodes from the list of HSZ nodes.
850      */
851         FreeAndRemoveHSZNodes( idInst, this_instance );
852     
853         /* OK now delete the instance handle itself */
854
855         if ( DDE_Handle_Table_Base == this_instance )
856         {
857                 /* special case - the first/only entry
858                 */
859                 DDE_Handle_Table_Base = this_instance->Next_Entry;
860         } else
861         {
862                 /* general case
863                 */
864                 reference_inst = DDE_Handle_Table_Base;
865                 while ( reference_inst->Next_Entry != this_instance )
866                 {
867                         reference_inst = this_instance->Next_Entry;
868                 }
869                 reference_inst->Next_Entry = this_instance->Next_Entry;
870         }
871         /* release the mutex and the heap entry
872         */
873         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE,this_instance)) 
874         {
875                 /* should record something here, but nothing left to hang it from !!
876                 */
877                 return FALSE;
878         }
879     return TRUE;
880 }
881
882
883 /*****************************************************************
884  * DdeConnectList16 [DDEML.4]
885  */
886
887 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
888                  HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
889 {
890     return DdeConnectList(idInst, hszService, hszTopic, hConvList, 
891                             (LPCONVCONTEXT)pCC);
892 }
893
894
895 /******************************************************************************
896  * DdeConnectList [USER32.93]  Establishes conversation with DDE servers
897  *
898  * PARAMS
899  *    idInst     [I] Instance identifier
900  *    hszService [I] Handle to service name string
901  *    hszTopic   [I] Handle to topic name string
902  *    hConvList  [I] Handle to conversation list
903  *    pCC        [I] Pointer to structure with context data
904  *
905  * RETURNS
906  *    Success: Handle to new conversation list
907  *    Failure: 0
908  */
909 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
910                  HCONVLIST hConvList, LPCONVCONTEXT pCC )
911 {
912     FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
913           hConvList,pCC);
914     return 1;
915 }
916
917
918 /*****************************************************************
919  * DdeQueryNextServer16 [DDEML.5]
920  */
921 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
922 {
923     return DdeQueryNextServer(hConvList, hConvPrev);
924 }
925
926
927 /*****************************************************************
928  * DdeQueryNextServer [USER32.112]
929  */
930 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
931 {
932     FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
933     return 0;
934 }
935
936 /*****************************************************************
937  * DdeQueryStringA [USER32.113]
938  *
939  *****************************************************************
940  *
941  *      Change History
942  *
943  *  Vn       Date       Author                  Comment
944  *
945  *  1.0      Dec 1998  Corel/Macadamian    Initial version
946  *  1.1      Mar 1999  Keith Matthews      Added links to instance table and related processing
947  *
948  */
949 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
950 {
951     DWORD ret = 0;
952     CHAR pString[MAX_BUFFER_LEN];
953     DDE_HANDLE_ENTRY *reference_inst;
954
955     FIXME(
956          "(%ld, 0x%x, %p, %ld, %d): partial stub\n",
957          idInst,
958          hsz,
959          psz, 
960          cchMax,
961          iCodePage);
962   if ( DDE_Max_Assigned_Instance == 0 )
963   {
964           /*  Nothing has been initialised - exit now ! */
965           /*  needs something for DdeGetLAstError even if the manual doesn't say so */
966           return FALSE;
967   }
968   
969         if ( !WaitForMutex(handle_mutex) )
970         {
971                 return FALSE;
972         }
973
974   TRACE("Handle Mutex created/reserved\n");
975
976   /*  First check instance 
977   */
978   reference_inst = Find_Instance_Entry(idInst);
979   if ( reference_inst == NULL )
980   {
981         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
982         /*
983         Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
984         */
985         return FALSE;
986   }
987
988     if( iCodePage == CP_WINANSI )
989     {
990         /* If psz is null, we have to return only the length
991          * of the string.
992          */
993         if( psz == NULL )
994         {
995             psz = pString;
996             cchMax = MAX_BUFFER_LEN;
997 }
998
999         ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
1000   } else {
1001         Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1002     }
1003    TRACE("returning pointer\n"); 
1004     return ret;
1005 }
1006
1007 /*****************************************************************
1008  * DdeQueryStringW [USER32.114]
1009  *
1010  *****************************************************************
1011  *
1012  *      Change History
1013  *
1014  *  Vn       Date       Author                  Comment
1015  *
1016  *  1.0      Dec 1998  Corel/Macadamian    Initial version
1017  *
1018  */
1019
1020 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1021 {
1022     DWORD ret = 0;
1023     WCHAR pString[MAX_BUFFER_LEN];
1024     int factor = 1;
1025
1026     FIXME(
1027          "(%ld, 0x%x, %p, %ld, %d): stub\n",
1028          idInst,
1029          hsz,
1030          psz, 
1031          cchMax,
1032          iCodePage);
1033
1034     if( iCodePage == CP_WINUNICODE )
1035     {
1036         /* If psz is null, we have to return only the length
1037          * of the string.
1038          */
1039         if( psz == NULL )
1040         {
1041             psz = pString;
1042             cchMax = MAX_BUFFER_LEN;
1043             /* Note: According to documentation if the psz parameter
1044              * was NULL this API must return the length of the string in bytes.
1045              */
1046             factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1047         }
1048         ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1049     }
1050     return ret;
1051 }
1052
1053 /*****************************************************************
1054 *
1055 *               DdeQueryString16 (DDEML.23)
1056 *
1057 ******************************************************************
1058  *
1059  *      Change History
1060  *
1061  *  Vn       Date       Author                  Comment
1062  *
1063  *  1.0      March 1999 K Matthews              stub only
1064  */
1065
1066 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, INT16 codepage)
1067 {
1068         FIXME("(%ld, 0x%x, %p, %ld, %d): stub \n", 
1069          idInst,
1070          hsz,
1071          lpsz, 
1072          cchMax,
1073          codepage);
1074         return 0;
1075 }
1076
1077
1078 /*****************************************************************
1079  *            DdeDisconnectList (DDEML.6)
1080  */
1081 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1082 {
1083     return (BOOL16)DdeDisconnectList(hConvList);
1084 }
1085
1086
1087 /******************************************************************************
1088  * DdeDisconnectList [USER32.98]  Destroys list and terminates conversations
1089  *
1090  * RETURNS
1091  *    Success: TRUE
1092  *    Failure: FALSE
1093  */
1094 BOOL WINAPI DdeDisconnectList(
1095     HCONVLIST hConvList) /* [in] Handle to conversation list */
1096 {
1097     FIXME("(%d): stub\n", hConvList);
1098     return TRUE;
1099 }
1100
1101
1102 /*****************************************************************
1103  *            DdeConnect16   (DDEML.7)
1104  */
1105 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1106                            LPCONVCONTEXT16 pCC )
1107 {
1108     FIXME("empty stub\n" );
1109     return 0;
1110 }
1111
1112
1113 /*****************************************************************
1114  *            DdeConnect   (USER32.92)
1115  */
1116 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1117                            LPCONVCONTEXT pCC )
1118 {
1119     FIXME("(0x%lx,%d,%d,%p): stub\n",idInst,hszService,hszTopic,
1120           pCC);
1121     return 0;
1122 }
1123
1124
1125 /*****************************************************************
1126  *            DdeDisconnect16   (DDEML.8)
1127  */
1128 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1129 {
1130     return (BOOL16)DdeDisconnect( hConv );
1131 }
1132
1133 /*****************************************************************
1134  *            DdeSetUserHandle16 (DDEML.10)
1135  */
1136 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1137 {
1138     FIXME("(%d,%ld,%ld): stub\n",hConv,id, hUser );
1139     return 0;
1140 }
1141
1142 /*****************************************************************
1143  *            DdeCreateDataHandle16 (DDEML.14)
1144  */
1145 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb, 
1146                                      DWORD cbOff, HSZ hszItem, UINT16 wFmt, 
1147                                      UINT16 afCmd )
1148 {
1149     return DdeCreateDataHandle(idInst,
1150                                 pSrc,
1151                                 cb,
1152                                 cbOff,
1153                                 hszItem,
1154                                 wFmt,
1155                                 afCmd);
1156 }
1157
1158 /*****************************************************************
1159  *            DdeCreateDataHandle (USER32.94)
1160  */
1161 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb, 
1162                                        DWORD cbOff, HSZ hszItem, UINT wFmt, 
1163                                        UINT afCmd )
1164 {
1165     FIXME(
1166           "(%ld,%p,%ld,%ld,0x%x,%d,%d): stub\n",
1167           idInst,
1168           pSrc,
1169           cb,
1170           cbOff,
1171            hszItem,
1172           wFmt, 
1173           afCmd );
1174
1175     return 0;
1176 }
1177
1178 /*****************************************************************
1179  *            DdeDisconnect   (USER32.97)
1180  */
1181 BOOL WINAPI DdeDisconnect( HCONV hConv )
1182 {
1183     FIXME("empty stub\n" );
1184     return 0;
1185 }
1186
1187
1188 /*****************************************************************
1189  *            DdeReconnect   (DDEML.37) (USER32.115)
1190  */
1191 HCONV WINAPI DdeReconnect( HCONV hConv )
1192 {
1193     FIXME("empty stub\n" );
1194     return 0;
1195 }
1196
1197
1198 /*****************************************************************
1199  *            DdeCreateStringHandle16   (DDEML.21)
1200  *
1201  *****************************************************************
1202  *
1203  *      Change History
1204  *
1205  *  Vn       Date       Author                  Comment
1206  *
1207  *  1.0      ?          ?                       basic stub
1208  *  1.1      June 1999  Keith Matthews          amended onward call to supply default
1209  *                                              code page if none supplied by caller
1210  */
1211 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1212 {
1213     if  ( codepage )
1214     {
1215     return DdeCreateStringHandleA( idInst, str, codepage );
1216      } else {
1217         TRACE("Default codepage supplied\n");
1218          return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1219      }
1220 }
1221
1222
1223 /*****************************************************************
1224  * DdeCreateStringHandleA [USER32.95]
1225  *
1226  * RETURNS
1227  *    Success: String handle
1228  *    Failure: 0
1229  *
1230  *****************************************************************
1231  *
1232  *      Change History
1233  *
1234  *  Vn       Date       Author                  Comment
1235  *
1236  *  1.0      Dec 1998  Corel/Macadamian    Initial version
1237  *  1.1      Mar 1999  Keith Matthews      Added links to instance table and related processing
1238  *
1239  */
1240 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1241 {
1242   HSZ hsz = 0;
1243   DDE_HANDLE_ENTRY *reference_inst;
1244   TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1245   
1246
1247   if ( DDE_Max_Assigned_Instance == 0 )
1248   {
1249           /*  Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1250           return FALSE;
1251   }
1252   
1253         if ( !WaitForMutex(handle_mutex) )
1254         {
1255                 return DMLERR_SYS_ERROR;
1256         }
1257
1258   TRACE("Handle Mutex created/reserved\n");
1259
1260   /*  First check instance 
1261   */
1262   reference_inst = Find_Instance_Entry(idInst);
1263   if ( reference_inst == NULL )
1264   {
1265         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1266         /*
1267         Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1268         */
1269         return 0;
1270   }
1271   
1272   if (codepage==CP_WINANSI)
1273   {
1274       hsz = GlobalAddAtomA (psz);
1275       /* Save the handle so we know to clean it when
1276        * uninitialize is called.
1277        */
1278       TRACE("added atom %s with HSZ 0x%x, \n",debugstr_a(psz),hsz);
1279       InsertHSZNode( hsz, reference_inst );
1280       if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) 
1281         {
1282                 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1283                 return 0;
1284         }
1285       TRACE("Returning pointer\n");
1286       return hsz;
1287   } else {
1288         Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1289   }
1290     TRACE("Returning error\n");
1291     return 0;  
1292 }
1293
1294
1295 /******************************************************************************
1296  * DdeCreateStringHandleW [USER32.96]  Creates handle to identify string
1297  *
1298  * RETURNS
1299  *    Success: String handle
1300  *    Failure: 0
1301  *
1302  *****************************************************************
1303  *
1304  *      Change History
1305  *
1306  *  Vn       Date       Author                  Comment
1307  *
1308  *  1.0      Dec 1998  Corel/Macadamian    Initial version
1309  *  1.1      Mar 1999  Keith Matthews      Added links to instance table and related processing
1310  *
1311  */
1312 HSZ WINAPI DdeCreateStringHandleW(
1313     DWORD idInst,   /* [in] Instance identifier */
1314     LPCWSTR psz,    /* [in] Pointer to string */
1315     INT codepage) /* [in] Code page identifier */
1316 {
1317    DDE_HANDLE_ENTRY *reference_inst;
1318    HSZ hsz = 0;
1319
1320    TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1321   
1322
1323   if ( DDE_Max_Assigned_Instance == 0 )
1324   {
1325           /*  Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1326           return FALSE;
1327   }
1328   
1329         if ( !WaitForMutex(handle_mutex) )
1330         {
1331                 return DMLERR_SYS_ERROR;
1332         }
1333
1334   TRACE("CreateString - Handle Mutex created/reserved\n");
1335   
1336   /*  First check instance 
1337   */
1338   reference_inst = Find_Instance_Entry(idInst);
1339   if ( reference_inst == NULL )
1340   {
1341         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1342         /*
1343         Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1344         */
1345         return 0;
1346   }
1347
1348     FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1349
1350   if (codepage==CP_WINUNICODE)
1351   /*
1352   Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1353   */
1354   {
1355       hsz = GlobalAddAtomW (psz);
1356       /* Save the handle so we know to clean it when
1357        * uninitialize is called.
1358        */
1359       InsertHSZNode( hsz, reference_inst );
1360       if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) 
1361         {
1362                 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1363                 return 0;
1364         }
1365       TRACE("Returning pointer\n");
1366       return hsz;
1367    } else {
1368         Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1369 }
1370     TRACE("Returning error\n");
1371   return 0;
1372 }
1373
1374
1375 /*****************************************************************
1376  *            DdeFreeStringHandle16   (DDEML.22)
1377  */
1378 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1379 {
1380         FIXME("idInst %ld hsz 0x%x\n",idInst,hsz);
1381     return (BOOL)DdeFreeStringHandle( idInst, hsz );
1382 }
1383
1384
1385 /*****************************************************************
1386  *            DdeFreeStringHandle   (USER32.101)
1387  * RETURNS: success: nonzero
1388  *          fail:    zero
1389  *
1390  *****************************************************************
1391  *
1392  *      Change History
1393  *
1394  *  Vn       Date       Author                  Comment
1395  *
1396  *  1.0      Dec 1998  Corel/Macadamian    Initial version
1397  *  1.1      Apr 1999  Keith Matthews      Added links to instance table and related processing
1398  *
1399  */
1400 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1401 {
1402     DDE_HANDLE_ENTRY *reference_inst;
1403     TRACE("(%ld,%d): \n",idInst,hsz);
1404   if ( DDE_Max_Assigned_Instance == 0 )
1405 {
1406           /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1407           return TRUE;
1408   }
1409
1410         if ( !WaitForMutex(handle_mutex) )
1411         {
1412                 return DMLERR_SYS_ERROR;
1413         }
1414
1415   TRACE("Handle Mutex created/reserved\n");
1416
1417   /*  First check instance 
1418   */
1419   reference_inst = Find_Instance_Entry(idInst);
1420   if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1421   {
1422         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
1423           /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1424           return TRUE;
1425
1426   }
1427
1428     /* Remove the node associated with this HSZ.
1429      */
1430     RemoveHSZNode( hsz , reference_inst);
1431     /* Free the string associated with this HSZ.
1432      */
1433   Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1434     return GlobalDeleteAtom (hsz) ? 0 : hsz;
1435 }
1436
1437
1438 /*****************************************************************
1439  *            DdeFreeDataHandle16   (DDEML.19)
1440  */
1441 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1442 {
1443     return (BOOL)DdeFreeDataHandle( hData );
1444 }
1445
1446
1447 /*****************************************************************
1448  *            DdeFreeDataHandle   (USER32.100)
1449  */
1450 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1451 {
1452     FIXME("empty stub\n" );
1453     return TRUE;
1454 }
1455
1456
1457
1458
1459 /*****************************************************************
1460  *            DdeKeepStringHandle16   (DDEML.24)
1461  */
1462 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1463 {
1464     return (BOOL)DdeKeepStringHandle( idInst, hsz );
1465 }
1466
1467
1468 /*****************************************************************
1469  *            DdeKeepStringHandle  (USER32.108)
1470  *
1471  * RETURNS: success: nonzero
1472  *          fail:    zero
1473  *
1474  *****************************************************************
1475  *
1476  *      Change History
1477  *
1478  *  Vn       Date       Author                  Comment
1479  *
1480  *  1.0      ?           ?                 Stub only
1481  *  1.1      Jun 1999  Keith Matthews      First cut implementation
1482  *
1483  */
1484 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1485 {
1486
1487   DDE_HANDLE_ENTRY *reference_inst;
1488   TRACE("(%ld,%d): \n",idInst,hsz);
1489   if ( DDE_Max_Assigned_Instance == 0 )
1490   {
1491           /*  Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1492           return FALSE;
1493   }
1494
1495
1496         if ( !WaitForMutex(handle_mutex) )
1497         {
1498                 return FALSE;
1499         }
1500
1501   TRACE("Handle Mutex created/reserved\n");
1502
1503   /*  First check instance
1504   */
1505   reference_inst = Find_Instance_Entry(idInst);
1506   if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1507   {
1508         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
1509           /*  Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1510           return FALSE;
1511     return FALSE;
1512    }
1513   DdeReserveAtom(reference_inst,hsz);
1514   Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1515     return TRUE;
1516 }
1517
1518
1519 /*****************************************************************
1520  *            DdeClientTransaction16  (DDEML.11)
1521  */
1522 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1523                                         HCONV hConv, HSZ hszItem, UINT16 wFmt,
1524                                         UINT16 wType, DWORD dwTimeout,
1525                                         LPDWORD pdwResult )
1526 {
1527     return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1528                                    wFmt, wType, dwTimeout, pdwResult );
1529 }
1530
1531
1532 /*****************************************************************
1533  *            DdeClientTransaction  (USER32.90)
1534  */
1535 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1536                                         HCONV hConv, HSZ hszItem, UINT wFmt,
1537                                         UINT wType, DWORD dwTimeout,
1538                                         LPDWORD pdwResult )
1539 {
1540     FIXME("empty stub\n" );
1541     return 0;
1542 }
1543
1544 /*****************************************************************
1545  *
1546  *            DdeAbandonTransaction16 (DDEML.12)
1547  *
1548  */
1549 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv, 
1550                                      DWORD idTransaction )
1551 {
1552     FIXME("empty stub\n" );
1553     return TRUE;
1554 }
1555
1556
1557 /*****************************************************************
1558  *
1559  *            DdeAbandonTransaction (USER32.87)
1560  *
1561 ******************************************************************
1562  *
1563  *      Change History
1564  *
1565  *  Vn       Date       Author                  Comment
1566  *
1567  *  1.0      March 1999 K Matthews              stub only
1568  */
1569 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv, 
1570                                      DWORD idTransaction )
1571 {
1572     FIXME("empty stub\n" );
1573     return TRUE;
1574 }
1575
1576 /*****************************************************************
1577  * DdePostAdvise16 [DDEML.13]
1578  */
1579 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1580 {
1581     return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1582 }
1583
1584
1585 /******************************************************************************
1586  * DdePostAdvise [USER32.110]  Send transaction to DDE callback function.
1587  *
1588  * RETURNS
1589  *    Success: TRUE
1590  *    Failure: FALSE
1591  */
1592 BOOL WINAPI DdePostAdvise(
1593     DWORD idInst, /* [in] Instance identifier */
1594     HSZ hszTopic, /* [in] Handle to topic name string */
1595     HSZ hszItem)  /* [in] Handle to item name string */
1596 {
1597     FIXME("(%ld,%d,%d): stub\n",idInst,hszTopic,hszItem);
1598     return TRUE;
1599 }
1600
1601
1602 /*****************************************************************
1603  *            DdeAddData16 (DDEML.15)
1604  */
1605 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1606                             DWORD cbOff )
1607 {
1608     FIXME("empty stub\n" );
1609     return 0;
1610 }
1611
1612 /*****************************************************************
1613  *
1614  *            DdeAddData (USER32.89)
1615  *
1616 ******************************************************************
1617  *
1618  *      Change History
1619  *
1620  *  Vn       Date       Author                  Comment
1621  *
1622  *  1.0      March 1999 K Matthews              stub only
1623  */
1624 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1625                             DWORD cbOff )
1626 {
1627     FIXME("empty stub\n" );
1628     return 0;
1629 }
1630
1631
1632 /*****************************************************************
1633  *
1634  *            DdeImpersonateClient (USER32.105)
1635  *
1636 ******************************************************************
1637  *
1638  *      Change History
1639  *
1640  *  Vn       Date       Author                  Comment
1641  *
1642  *  1.0      March 1999 K Matthews              stub only
1643  */
1644
1645 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1646 {
1647     FIXME("empty stub\n" );
1648     return TRUE;
1649 }
1650
1651
1652 /*****************************************************************
1653  *
1654  *            DdeSetQualityOfService (USER32.116)
1655  *
1656 ******************************************************************
1657  *
1658  *      Change History
1659  *
1660  *  Vn       Date       Author                  Comment
1661  *
1662  *  1.0      March 1999 K Matthews              stub only
1663  */
1664
1665 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1666                                         PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1667 {
1668     FIXME("empty stub\n" );
1669     return TRUE;
1670 }
1671
1672 /*****************************************************************
1673  *
1674  *            DdeSetUserHandle (USER32.117)
1675  *
1676 ******************************************************************
1677  *
1678  *      Change History
1679  *
1680  *  Vn       Date       Author                  Comment
1681  *
1682  *  1.0      March 1999 K Matthews              stub only
1683  */
1684
1685 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1686 {
1687     FIXME("empty stub\n" );
1688     return TRUE;
1689 }
1690
1691 /******************************************************************************
1692  * DdeGetData [USER32.102]  Copies data from DDE object ot local buffer
1693  *
1694  * RETURNS
1695  *    Size of memory object associated with handle
1696  */
1697 DWORD WINAPI DdeGetData(
1698     HDDEDATA hData, /* [in] Handle to DDE object */
1699     LPBYTE pDst,    /* [in] Pointer to destination buffer */
1700     DWORD cbMax,    /* [in] Amount of data to copy */
1701     DWORD cbOff)    /* [in] Offset to beginning of data */
1702 {
1703     FIXME("(%d,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1704     return cbMax;
1705 }
1706
1707
1708 /*****************************************************************
1709  * DdeGetData16 [DDEML.16]
1710  */
1711 DWORD WINAPI DdeGetData16(
1712     HDDEDATA hData,
1713     LPBYTE pDst,
1714     DWORD cbMax, 
1715     DWORD cbOff)
1716 {
1717     return DdeGetData(hData, pDst, cbMax, cbOff);
1718 }
1719
1720
1721 /*****************************************************************
1722  *            DdeAccessData16 (DDEML.17)
1723  */
1724 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1725 {
1726      return DdeAccessData(hData, pcbDataSize);
1727 }
1728
1729 /*****************************************************************
1730  *            DdeAccessData (USER32.88)
1731  */
1732 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1733 {
1734      FIXME("(%d,%p): stub\n", hData, pcbDataSize);
1735      return 0;
1736 }
1737
1738 /*****************************************************************
1739  *            DdeUnaccessData16 (DDEML.18)
1740  */
1741 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1742 {
1743      return DdeUnaccessData(hData);
1744 }
1745
1746 /*****************************************************************
1747  *            DdeUnaccessData (USER32.118)
1748  */
1749 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1750 {
1751      FIXME("(0x%x): stub\n", hData);
1752
1753      return 0;
1754 }
1755
1756 /*****************************************************************
1757  *            DdeEnableCallback16 (DDEML.26)
1758  */
1759 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1760 {
1761      return DdeEnableCallback(idInst, hConv, wCmd);
1762 }
1763
1764 /*****************************************************************
1765  *            DdeEnableCallback (USER32.99)
1766  */
1767 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1768 {
1769      FIXME("(%ld, 0x%x, %d) stub\n", idInst, hConv, wCmd);
1770
1771      return 0;
1772 }
1773
1774 /*****************************************************************
1775  *            DdeNameService16  (DDEML.27)
1776  */
1777 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1778                                   UINT16 afCmd )
1779 {
1780     return DdeNameService( idInst, hsz1, hsz2, afCmd );
1781 }
1782
1783
1784 /******************************************************************************
1785  * DdeNameService [USER32.109]  {Un}registers service name of DDE server
1786  *
1787  * PARAMS
1788  *    idInst [I] Instance identifier
1789  *    hsz1   [I] Handle to service name string
1790  *    hsz2   [I] Reserved
1791  *    afCmd  [I] Service name flags
1792  *
1793  * RETURNS
1794  *    Success: Non-zero
1795  *    Failure: 0
1796  *
1797  *****************************************************************
1798  *
1799  *      Change History
1800  *
1801  *  Vn       Date       Author                  Comment
1802  *
1803  *  1.0      ?            ?                Stub
1804  *  1.1      Apr 1999  Keith Matthews      Added trap for non-existent instance (uninitialised instance 0
1805  *                                              used by some MS programs for unfathomable reasons)
1806  *  1.2      May 1999  Keith Matthews      Added parameter validation and basic service name handling.
1807  *                                         Still needs callback parts
1808  *
1809  */
1810 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1811                 UINT afCmd )
1812 {
1813   ServiceNode* this_service, *reference_service ;
1814   DDE_HANDLE_ENTRY *this_instance;
1815   DDE_HANDLE_ENTRY *reference_inst;
1816   this_service = NULL;
1817
1818   FIXME("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1819
1820   if ( DDE_Max_Assigned_Instance == 0 )
1821   {
1822           /*  Nothing has been initialised - exit now ! 
1823            *    needs something for DdeGetLastError */
1824           return 0L;
1825   }
1826
1827         if ( !WaitForMutex(handle_mutex) )
1828         {
1829                 return DMLERR_SYS_ERROR;
1830         }
1831
1832    TRACE("Handle Mutex created/reserved\n");
1833
1834    /*  First check instance
1835    */
1836    reference_inst = Find_Instance_Entry(idInst);
1837    this_instance = reference_inst;
1838    if  (reference_inst == NULL)
1839    {
1840         TRACE("Instance not found as initialised\n");
1841         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return TRUE;
1842           /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1843           return FALSE;
1844
1845    }
1846
1847   if ( hsz2 != 0L )
1848   {
1849         /*      Illegal, reserved parameter
1850          */
1851         reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1852         Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1853         FIXME("Reserved parameter no-zero !!\n");
1854         return FALSE;
1855   }
1856   if ( hsz1 == 0L )
1857   {
1858         /*
1859          *      General unregister situation
1860          */
1861         if ( afCmd != DNS_UNREGISTER )
1862         {
1863                 /*      don't know if we should check this but it makes sense
1864                  *      why supply REGISTER or filter flags if de-registering all
1865                  */
1866                 TRACE("General unregister unexpected flags\n");
1867                 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1868                 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1869                 return FALSE;
1870         }
1871         /*      Loop to find all registered service and de-register them
1872          */
1873         if ( reference_inst->ServiceNames == NULL )
1874         {
1875                 /*  None to unregister !!  
1876                  */
1877                 TRACE("General de-register - nothing registered\n");
1878                 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1879                 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1880                 return FALSE;
1881         }  else
1882         {
1883                 this_service = reference_inst->ServiceNames;
1884                 while ( this_service->next != NULL)
1885                 {
1886                         TRACE("general deregister - iteration\n");
1887                         reference_service = this_service;
1888                         this_service = this_service->next;
1889                         DdeReleaseAtom(reference_inst,reference_service->hsz);
1890                         HeapFree(GetProcessHeap(), 0, reference_service); /* finished - release heap space used as work store */
1891                 }
1892                 DdeReleaseAtom(reference_inst,this_service->hsz);
1893                 HeapFree(GetProcessHeap(), 0, this_service); /* finished - release heap space used as work store */
1894                 reference_inst->ServiceNames = NULL;
1895                 TRACE("General de-register - finished\n");
1896         }
1897         Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1898         return TRUE;
1899   }
1900   TRACE("Specific name action detected\n");
1901   if ( afCmd & DNS_REGISTER )
1902   {
1903         /* Register new service name
1904          */
1905
1906         this_service = Find_Service_Name( hsz1, reference_inst );
1907         if ( this_service )
1908                 ERR("Trying to register already registered service!\n");
1909         else
1910         {
1911                 TRACE("Adding service name\n");
1912
1913                 DdeReserveAtom(reference_inst, hsz1);
1914
1915                 this_service = (ServiceNode*)HeapAlloc( GetProcessHeap(), 0, sizeof(ServiceNode) );
1916                 this_service->hsz = hsz1;
1917                 this_service->FilterOn = TRUE;
1918
1919                 this_service->next = reference_inst->ServiceNames;
1920                 reference_inst->ServiceNames = this_service;
1921         }
1922   }
1923   if ( afCmd & DNS_UNREGISTER )
1924   {
1925         /*      De-register service name
1926          */
1927
1928         ServiceNode **pServiceNode = &reference_inst->ServiceNames;
1929         while ( *pServiceNode && (*pServiceNode)->hsz != hsz1 )
1930                 pServiceNode = &(*pServiceNode)->next;
1931
1932         this_service = *pServiceNode;
1933         if ( !this_service )
1934                 ERR("Trying to de-register unregistered service!\n");
1935         else
1936         {
1937                 *pServiceNode = this_service->next;
1938                 DdeReleaseAtom(reference_inst,this_service->hsz);
1939                 HeapFree(GetProcessHeap(), 0, this_service);
1940         }
1941   }
1942   if ( afCmd & DNS_FILTERON )
1943   {
1944         /*      Set filter flags on to hold notifications of connection
1945          *
1946          *      test coded this way as this is the default setting
1947          */
1948         this_service = Find_Service_Name( hsz1, reference_inst );
1949         if ( !this_service )
1950         {
1951                 /*  trying to filter where no service names !!
1952                  */
1953                 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1954                 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1955                 return FALSE;
1956         } else 
1957         {
1958                 this_service->FilterOn = TRUE;
1959         }
1960   }
1961   if ( afCmd & DNS_FILTEROFF )
1962   {
1963         /*      Set filter flags on to hold notifications of connection
1964          */
1965         this_service = Find_Service_Name( hsz1, reference_inst );
1966         if ( !this_service )
1967         {
1968                 /*  trying to filter where no service names !!
1969                  */
1970                 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1971                 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1972                 return FALSE;
1973         } else 
1974         {
1975                 this_service->FilterOn = FALSE;
1976         }
1977   }
1978   Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1979   return TRUE;
1980 }
1981
1982
1983 /*****************************************************************
1984  *            DdeGetLastError16  (DDEML.20)
1985  */
1986 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1987 {
1988     return (UINT16)DdeGetLastError( idInst );
1989 }
1990
1991
1992 /******************************************************************************
1993  * DdeGetLastError [USER32.103]  Gets most recent error code
1994  *
1995  * PARAMS
1996  *    idInst [I] Instance identifier
1997  *
1998  * RETURNS
1999  *    Last error code
2000  *
2001  *****************************************************************
2002  *
2003  *      Change History
2004  *
2005  *  Vn       Date       Author                  Comment
2006  *
2007  *  1.0      ?            ?                Stub
2008  *  1.1      Apr 1999  Keith Matthews      Added response for non-existent instance (uninitialised instance 0
2009  *                                              used by some MS programs for unfathomable reasons)
2010  *  1.2      May 1999  Keith Matthews      Added interrogation of Last_Error for instance handle where found.
2011  *
2012  */
2013 UINT WINAPI DdeGetLastError( DWORD idInst )
2014 {
2015     DWORD       error_code;
2016     DDE_HANDLE_ENTRY *reference_inst;
2017
2018     FIXME("(%ld): stub\n",idInst);
2019
2020     if ( DDE_Max_Assigned_Instance == 0 )
2021     {
2022           /*  Nothing has been initialised - exit now ! */
2023           return DMLERR_DLL_NOT_INITIALIZED;
2024     }
2025
2026         if ( !WaitForMutex(handle_mutex) )
2027         {
2028                 return DMLERR_SYS_ERROR;
2029         }
2030
2031    TRACE("Handle Mutex created/reserved\n");
2032
2033    /*  First check instance
2034    */
2035    reference_inst = Find_Instance_Entry(idInst);
2036    if  (reference_inst == NULL) 
2037    {
2038         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
2039           /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2040           return DMLERR_DLL_NOT_INITIALIZED;
2041
2042    }
2043     error_code = reference_inst->Last_Error;
2044     reference_inst->Last_Error = 0;
2045     Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
2046    return error_code;
2047 }
2048
2049
2050 /*****************************************************************
2051  *            DdeCmpStringHandles16 (DDEML.36)
2052  */
2053 INT16 WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2054 {
2055      return DdeCmpStringHandles(hsz1, hsz2);
2056 }
2057
2058 /*****************************************************************
2059  *            DdeCmpStringHandles (USER32.91)
2060  *
2061  * Compares the value of two string handles.  This comparison is
2062  * not case sensitive.
2063  *
2064  * Returns:
2065  * -1 The value of hsz1 is zero or less than hsz2
2066  * 0  The values of hsz 1 and 2 are the same or both zero.
2067  * 1  The value of hsz2 is zero of less than hsz1
2068  */
2069 INT WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2070 {
2071     CHAR psz1[MAX_BUFFER_LEN];
2072     CHAR psz2[MAX_BUFFER_LEN];
2073     int ret = 0;
2074     int ret1, ret2;
2075
2076     TRACE("handle 1, handle 2\n" );
2077
2078     ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2079     ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2080     /* Make sure we found both strings.
2081      */
2082     if( ret1 == 0 && ret2 == 0 )
2083     {
2084         /* If both are not found, return both  "zero strings".
2085          */
2086         ret = 0;
2087     }
2088     else if( ret1 == 0 )
2089     {
2090         /* If hsz1 is a not found, return hsz1 is "zero string".
2091          */
2092         ret = -1;
2093     }
2094     else if( ret2 == 0 )
2095     {
2096         /* If hsz2 is a not found, return hsz2 is "zero string".
2097          */
2098         ret = 1;
2099     }
2100     else
2101     {
2102         /* Compare the two strings we got ( case insensitive ).
2103          */
2104         ret = strcasecmp( psz1, psz2 );
2105         /* Since strcmp returns any number smaller than
2106          * 0 when the first string is found to be less than
2107          * the second one we must make sure we are returning
2108          * the proper values.
2109          */
2110         if( ret < 0 )
2111         {
2112             ret = -1;
2113         }
2114         else if( ret > 0 )
2115         {
2116             ret = 1;
2117         }
2118     }
2119
2120     return ret;
2121 }
2122
2123 /*****************************************************************
2124  *            PackDDElParam (USER32.414)
2125  *
2126  * RETURNS
2127  *   success: nonzero
2128  *   failure: zero
2129  */
2130 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2131 {
2132     FIXME("stub.\n");
2133     return 0;
2134 }
2135
2136
2137 /*****************************************************************
2138  *            UnpackDDElParam (USER32.562)
2139  *
2140  * RETURNS
2141  *   success: nonzero
2142  *   failure: zero
2143  */
2144 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
2145                               UINT *uiLo, UINT *uiHi)
2146 {
2147     FIXME("stub.\n");
2148     return 0;
2149 }
2150
2151
2152 /*****************************************************************
2153  *            FreeDDElParam (USER32.204)
2154  *
2155  * RETURNS
2156  *   success: nonzero
2157  *   failure: zero
2158  */
2159 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
2160 {
2161     FIXME("stub.\n");
2162     return 0;
2163 }
2164
2165 /*****************************************************************
2166  *            ReuseDDElParam (USER32.446)
2167  *
2168  */
2169 UINT WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2170                              UINT uiLi, UINT uiHi)
2171 {
2172     FIXME("stub.\n");
2173     return 0;
2174
2175
2176 /******************************************************************
2177  *              DdeQueryConvInfo16 (DDEML.9)
2178  *
2179  */
2180 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2181 {
2182         FIXME("stub.\n");
2183         return 0;
2184 }
2185
2186
2187 /******************************************************************
2188  *              DdeQueryConvInfo (USER32.111)
2189  *
2190  */
2191 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)
2192 {
2193         FIXME("stub.\n");
2194         return 0;
2195 }