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