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