Added an unknown VxD error code.
[wine] / dlls / user / ddeml.c
1 /*
2  * DDEML library
3  *
4  * Copyright 1997 Alexandre Julliard
5  * Copyright 1997 Len White
6  * Copyright 1999 Keith Matthews
7  */
8
9 /* Only empty stubs for now */
10
11 #include <stdlib.h>
12 #include <string.h>
13 #include "winbase.h"
14 #include "windef.h"
15 #include "wingdi.h"
16 #include "winuser.h"
17 #include "ddeml.h"
18 #include "ddeml16.h"
19 #include "winerror.h"
20 #include "heap.h"
21 #include "debugtools.h"
22 #include "winnt.h"
23
24 DEFAULT_DEBUG_CHANNEL(ddeml);
25
26 /* Has defined in atom.c file.
27  */
28 #define MAX_ATOM_LEN              255
29
30 /* Maximum buffer size ( including the '\0' ).
31  */
32 #define MAX_BUFFER_LEN            (MAX_ATOM_LEN + 1)
33
34 /*  typedef struct {
35         DWORD           nLength;
36         LPVOID          lpSecurityDescriptor;
37         BOOL            bInheritHandle;
38 }       SECURITY_ATTRIBUTES; */
39
40 /* This is a simple list to keep track of the strings created
41  * by DdeCreateStringHandle.  The list is used to free
42  * the strings whenever DdeUninitialize is called.
43  * This mechanism is not complete and does not handle multiple instances.
44  * Most of the DDE API use a DWORD parameter indicating which instance
45  * of a given program is calling them.  The API are supposed to
46  * associate the data to the instance that created it.
47  */
48 typedef struct tagHSZNode HSZNode;
49 struct tagHSZNode
50 {
51     HSZNode* next;
52     HSZ hsz;
53 };
54
55
56 typedef struct tagServiceNode ServiceNode;
57 struct tagServiceNode
58 {
59     ServiceNode* next;
60     HSZ hsz;
61     BOOL16              FilterOn;
62 };
63 typedef struct DDE_HANDLE_ENTRY {
64     BOOL16              Monitor;        /* have these two as full Booleans cos they'll be tested frequently */
65     BOOL16              Client_only;    /* bit wasteful of space but it will be faster */
66     BOOL16              Unicode;        /* Flag to indicate Win32 API used to initialise */
67     BOOL16              Win16;          /* flag to indicate Win16 API used to initialize */
68     DWORD               Instance_id;  /* needed to track monitor usage */
69     struct DDE_HANDLE_ENTRY    *Next_Entry;
70     HSZNode     *Node_list;
71     PFNCALLBACK         CallBack;
72     DWORD               CBF_Flags;
73     DWORD               Monitor_flags;
74     UINT              Txn_count;      /* count transactions open to simplify closure */
75     DWORD               Last_Error; 
76     ServiceNode*                ServiceNames;
77 } DDE_HANDLE_ENTRY;
78
79 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
80 static DWORD            DDE_Max_Assigned_Instance = 0;  /* OK for present, may have to worry about wrap-around later */
81 static const char       *DDEInstanceAccess = "DDEMaxInstance";
82 static const char       *DDEHandleAccess = "DDEHandleAccess";
83 static HANDLE           inst_count_mutex = 0;
84 static HANDLE           handle_mutex = 0;
85
86 #define TRUE    1
87 #define FALSE   0
88
89
90 /******************************************************************************
91  *            RemoveHSZNodes    (INTERNAL)
92  *
93  * Remove a node from the list of HSZ nodes.
94  *
95  ******************************************************************************
96  *
97  *      Change History
98  *
99  *  Vn       Date       Author                  Comment
100  *
101  *  1.0      Dec 1998  Corel/Macadamian    Initial version
102  *  1.1      Mar 1999  Keith Matthews      Added multiple instance handling
103  *
104  */
105 static void RemoveHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
106 {
107     HSZNode* pPrev = NULL;
108     HSZNode* pCurrent = NULL;
109
110     /* Set the current node at the start of the list.
111      */
112     pCurrent = reference_inst->Node_list;
113     /* While we have more nodes.
114      */
115     while( pCurrent != NULL )
116     {
117         /* If we found the node we were looking for.
118          */
119         if( pCurrent->hsz == hsz )
120         {
121             /* Remove the node.
122              */
123             /* If the first node in the list is to to be removed.
124              * Set the global list pointer to the next node.
125              */
126             if( pCurrent == reference_inst->Node_list )
127             {
128                 reference_inst->Node_list = pCurrent->next;
129             }
130             /* Just fix the pointers has to skip the current
131              * node so we can delete it.
132              */
133             else
134             {
135                 pPrev->next = pCurrent->next;
136             }
137             /* Destroy this node.
138              */
139             free( pCurrent );
140             break;
141         }
142         /* Save the previous node pointer.
143          */
144         pPrev = pCurrent;
145         /* Move on to the next node.
146          */
147         pCurrent = pCurrent->next;
148     }
149 }
150
151 /******************************************************************************
152  *            FreeAndRemoveHSZNodes    (INTERNAL)
153  *
154  * Frees up all the strings still allocated in the list and
155  * remove all the nodes from the list of HSZ nodes.
156  *
157  ******************************************************************************
158  *
159  *      Change History
160  *
161  *  Vn       Date       Author                  Comment
162  *
163  *  1.0      Dec 1998  Corel/Macadamian    Initial version
164  *  1.1      Mar 1999  Keith Matthews      Added multiple instance handling
165  *
166  */
167 static void FreeAndRemoveHSZNodes( DWORD idInst, DDE_HANDLE_ENTRY * reference_inst )
168 {
169     /* Free any strings created in this instance.
170      */
171     while( reference_inst->Node_list != NULL )
172     {
173         DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
174     }
175 }
176
177 /******************************************************************************
178  *            InsertHSZNode    (INTERNAL)
179  *
180  * Insert a node to the head of the list.
181  *
182  ******************************************************************************
183  *
184  *      Change History
185  *
186  *  Vn       Date       Author                  Comment
187  *
188  *  1.0      Dec 1998  Corel/Macadamian    Initial version
189  *  1.1      Mar 1999  Keith Matthews      Added instance handling
190  *  1.2      Jun 1999  Keith Matthews      Added Usage count handling
191  *
192  */
193 static void InsertHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
194 {
195     if( hsz != 0 )
196     {
197         HSZNode* pNew = NULL;
198         /* Create a new node for this HSZ.
199          */
200         pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
201         if( pNew != NULL )
202         {
203             /* Set the handle value.
204              */
205             pNew->hsz = hsz;
206             /* Attach the node to the head of the list. i.e most recently added is first
207              */
208             pNew->next = reference_inst->Node_list;
209
210             /* The new node is now at the head of the list
211              * so set the global list pointer to it.
212              */
213             reference_inst->Node_list = pNew;
214             TRACE("HSZ node list entry added\n");
215         }
216     }
217 }
218
219 /*****************************************************************************
220  *      Find_Instance_Entry
221  *
222  *      generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
223  *      for an instance Id, or NULL if the entry does not exist
224  *
225  *      ASSUMES the mutex protecting the handle entry list is reserved before calling
226  *
227  ******************************************************************************
228  *
229  *      Change History
230  *
231  *  Vn       Date       Author                  Comment
232  *
233  *  1.0      March 1999  Keith Matthews      1st implementation
234              */
235  DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
236 {
237         DDE_HANDLE_ENTRY * reference_inst;
238         reference_inst =  DDE_Handle_Table_Base;
239         while ( reference_inst != NULL )
240         {
241                 if ( reference_inst->Instance_id == InstId )
242                 {
243                         TRACE("Instance entry found\n");
244                         return reference_inst;
245         }
246                 reference_inst = reference_inst->Next_Entry;
247     }
248         TRACE("Instance entry missing\n");
249         return NULL;
250 }
251
252 /*****************************************************************************
253  *      Find_Service_Name
254  *
255  *      generic routine to return a pointer to the relevant ServiceNode
256  *      for a given service name, or NULL if the entry does not exist
257  *
258  *      ASSUMES the mutex protecting the handle entry list is reserved before calling
259  *
260  ******************************************************************************
261  *
262  *      Change History
263  *
264  *  Vn       Date       Author                  Comment
265  *
266  *  1.0      May 1999  Keith Matthews      1st implementation
267              */
268  ServiceNode *Find_Service_Name (HSZ Service_Name, DDE_HANDLE_ENTRY* this_instance)
269 {
270         ServiceNode * reference_name=  this_instance->ServiceNames;
271         while ( reference_name != NULL )
272         {
273                 if ( reference_name->hsz == Service_Name )
274                 {
275                         TRACE("Service Name found\n");
276                         return reference_name;
277         }
278                 reference_name = reference_name->next;
279     }
280         TRACE("Service name missing\n");
281         return NULL;
282 }
283
284
285 /******************************************************************************
286  *      Release_reserved_mutex
287  *
288  *      generic routine to release a reserved mutex
289  *
290  *
291  ******************************************************************************
292  *
293  *      Change History
294  *
295  *  Vn       Date       Author                  Comment
296  *
297  *  1.0      Jan 1999  Keith Matthews        Initial version
298  *  1.1      Mar 1999  Keith Matthews        Corrected Heap handling. Corrected re-initialisation handling
299  *  1.2      Aug 1999  Jürgen Schmied        Corrected error handling
300  *
301  */
302 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i , 
303     DDE_HANDLE_ENTRY *this_instance)
304 {
305         if (!ReleaseMutex(mutex))
306         {
307                 ERR("ReleaseMutex failed - %s mutex %li\n",mutex_name,GetLastError());
308                 HeapFree(GetProcessHeap(), 0, this_instance);
309                 if ( release_handle_m )
310                 {
311                         ReleaseMutex(handle_mutex);
312                 }
313                 return DMLERR_SYS_ERROR;
314          }
315         if ( release_this_i )
316         {
317                 HeapFree(GetProcessHeap(), 0, this_instance);
318         }
319         return DMLERR_NO_ERROR;
320 }
321
322 /******************************************************************************
323  *      WaitForMutex
324  *
325  *      generic routine to wait for the mutex
326  *
327  *
328  ******************************************************************************
329  *
330  *      Change History
331  *
332  *  Vn       Date       Author                  Comment
333  *
334  *  1.0      Aug 1999  Juergen Schmied       Initial version
335  *
336  */
337 static BOOL WaitForMutex (HANDLE mutex)
338 {
339         DWORD result;
340
341         result = WaitForSingleObject(mutex,1000);
342
343         /* both errors should never occur */
344         if (WAIT_TIMEOUT == result)
345         {
346                 ERR("WaitForSingleObject timed out\n");
347                 return FALSE;
348         }
349
350         if (WAIT_FAILED == result)
351         {
352                 ERR("WaitForSingleObject failed - error %li\n", GetLastError());
353                 return FALSE;
354         }
355         return TRUE;
356 }
357 /******************************************************************************
358  *              IncrementInstanceId
359  *
360  *      generic routine to increment the max instance Id and allocate a new application instance
361  *
362  ******************************************************************************
363  *
364  *      Change History
365  *
366  *  Vn       Date       Author                  Comment
367  *
368  *  1.0      Jan 1999  Keith Matthews        Initial version
369  *
370  */
371 DWORD IncrementInstanceId( DDE_HANDLE_ENTRY *this_instance)
372 {
373         SECURITY_ATTRIBUTES s_attrib;
374
375         /*  Need to set up Mutex in case it is not already present */
376         /* increment handle count & get value */
377         if ( !inst_count_mutex )
378         {
379                 s_attrib.bInheritHandle = TRUE;
380                 s_attrib.lpSecurityDescriptor = NULL;
381                 s_attrib.nLength = sizeof(s_attrib);
382                 inst_count_mutex = CreateMutexA(&s_attrib,0,DDEInstanceAccess); /* 1st time through */
383         } 
384         if ( inst_count_mutex )
385         {
386                 if ( !WaitForMutex(inst_count_mutex) )
387                 {
388                         return DMLERR_SYS_ERROR;
389                 }
390         } else
391         {
392                 ERR("CreateMutex failed - inst_count %li\n",GetLastError());
393                 Release_reserved_mutex (handle_mutex,"handle_mutex",0,1,this_instance);
394                 return DMLERR_SYS_ERROR;
395         }
396         DDE_Max_Assigned_Instance++;
397         this_instance->Instance_id = DDE_Max_Assigned_Instance;
398         TRACE("New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
399         if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0,this_instance)) return DMLERR_SYS_ERROR;
400         return DMLERR_NO_ERROR;
401 }
402
403 /******************************************************************************
404  *              FindNotifyMonitorCallbacks
405  *
406  *      Routine to find instances that need to be notified via their callback
407  *      of some event they are monitoring
408  *
409  ******************************************************************************
410  *
411  *      Change History
412  *
413  *  Vn       Date       Author                  Comment
414  *
415  *  1.0    May 1999    Keith Matthews       Initial Version
416  *
417  */
418
419 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
420 {
421         DDE_HANDLE_ENTRY *InstanceHandle;
422         InstanceHandle = DDE_Handle_Table_Base;
423         while ( InstanceHandle != NULL )
424         {
425                 if (  (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
426                 {
427                         /*   Found an instance registered as monitor and is not ourselves
428                          *      use callback to notify where appropriate
429                          */
430                 }
431                 InstanceHandle = InstanceHandle->Next_Entry;
432         }
433 }
434
435 /******************************************************************************
436  *              DdeReserveAtom
437  *
438  *      Routine to make an extra Add on an atom to reserve it a bit longer
439  *
440  ******************************************************************************
441  *
442  *      Change History
443  *
444  *  Vn       Date       Author                  Comment
445  *
446  *  1.0    Jun 1999    Keith Matthews       Initial Version
447  *
448  */
449
450 static void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
451 {
452   if ( reference_inst->Unicode)
453   {
454         WCHAR SNameBuffer[MAX_BUFFER_LEN];
455         GlobalGetAtomNameW(hsz,SNameBuffer,MAX_BUFFER_LEN);
456         GlobalAddAtomW(SNameBuffer);
457   } else {
458         CHAR SNameBuffer[MAX_BUFFER_LEN];
459         GlobalGetAtomNameA(hsz,SNameBuffer,MAX_BUFFER_LEN);
460         GlobalAddAtomA(SNameBuffer);
461   }
462 }
463
464
465 /******************************************************************************
466  *              DdeReleaseAtom
467  *
468  *      Routine to make a delete on an atom to release it a bit sooner
469  *
470  ******************************************************************************
471  *
472  *      Change History
473  *
474  *  Vn       Date       Author                  Comment
475  *
476  *  1.0    Jun 1999    Keith Matthews       Initial Version
477  *
478  */
479
480 static void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
481 {
482     GlobalDeleteAtom( hsz );
483 }
484
485 /******************************************************************************
486  *            DdeInitialize16   (DDEML.2)
487  */
488 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
489                                DWORD afCmd, DWORD ulRes)
490 {
491     TRACE("DdeInitialize16 called - calling DdeInitializeA\n");
492     return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
493                                     afCmd, ulRes);
494 }
495
496
497 /******************************************************************************
498  *            DdeInitializeA   (USER32.@)
499  */
500 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
501                                 DWORD afCmd, DWORD ulRes )
502 {
503     TRACE("DdeInitializeA called - calling DdeInitializeW\n");
504     return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
505 }
506
507
508 /******************************************************************************
509  * DdeInitializeW [USER32.@]
510  * Registers an application with the DDEML
511  *
512  * PARAMS
513  *    pidInst     [I] Pointer to instance identifier
514  *    pfnCallback [I] Pointer to callback function
515  *    afCmd       [I] Set of command and filter flags
516  *    ulRes       [I] Reserved
517  *
518  * RETURNS
519  *    Success: DMLERR_NO_ERROR
520  *    Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
521  *
522  ******************************************************************************
523  *
524  *      Change History
525  *
526  *  Vn       Date       Author                  Comment
527  *
528  *  1.0      Pre 1998  Alexandre/Len         Initial Stub
529  *  1.1      Jan 1999  Keith Matthews        Initial (near-)complete version
530  *  1.2      Mar 1999  Keith Matthews        Corrected Heap handling, CreateMutex failure handling
531  *
532  */
533 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
534                                 DWORD afCmd, DWORD ulRes )
535 {
536
537 /*  probably not really capable of handling multiple processes, but should handle
538  *      multiple instances within one process */
539
540     SECURITY_ATTRIBUTES *s_att= NULL;
541     SECURITY_ATTRIBUTES s_attrib;
542     DWORD               err_no = 0;
543     DDE_HANDLE_ENTRY *this_instance;
544     DDE_HANDLE_ENTRY *reference_inst;
545     s_att = &s_attrib;
546
547     if( ulRes )
548     {
549         ERR("Reserved value not zero?  What does this mean?\n");
550         FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
551               afCmd,ulRes);
552         /* trap this and no more until we know more */
553         return DMLERR_NO_ERROR;
554     }
555     if (!pfnCallback ) 
556     {
557         /*  this one may be wrong - MS dll seems to accept the condition, 
558             leave this until we find out more !! */
559
560
561         /* can't set up the instance with nothing to act as a callback */
562         TRACE("No callback provided\n");
563         return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
564      }
565
566      /* grab enough heap for one control struct - not really necessary for re-initialise
567       * but allows us to use same validation routines */
568      this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( GetProcessHeap(), 0, sizeof(DDE_HANDLE_ENTRY) );
569      if ( this_instance == NULL )
570      {
571         /* catastrophe !! warn user & abort */
572         ERR("Instance create failed - out of memory\n");
573         return DMLERR_SYS_ERROR;
574      }
575      this_instance->Next_Entry = NULL;
576      this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
577
578      /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
579
580      this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
581      this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
582      this_instance->CallBack=*pfnCallback;
583      this_instance->Txn_count=0;
584      this_instance->Unicode = TRUE;
585      this_instance->Win16 = FALSE;
586      this_instance->Node_list = NULL; /* node will be added later */
587      this_instance->Monitor_flags = afCmd & MF_MASK;
588      this_instance->ServiceNames = NULL;
589
590      /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
591
592      this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
593
594      if ( ! this_instance->Client_only )
595      {
596
597         /* Check for other way of setting Client-only !! */
598
599         this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
600                         ==CBF_FAIL_ALLSVRXACTIONS;
601      }
602
603      TRACE("instance created - checking validity \n");
604
605     if( *pidInst == 0 ) {
606         /*  Initialisation of new Instance Identifier */
607         TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
608         if ( DDE_Max_Assigned_Instance == 0 )
609         {
610             /*  Nothing has been initialised - exit now ! can return TRUE since effect is the same */
611             /*  Need to set up Mutex in case it is not already present */
612             s_att->bInheritHandle = TRUE;
613             s_att->lpSecurityDescriptor = NULL;
614             s_att->nLength = sizeof(s_att);
615             handle_mutex = CreateMutexA(s_att,0,DDEHandleAccess);
616             if ( !handle_mutex ) {
617                     ERR("CreateMutex failed - handle list  %li\n",GetLastError());
618                     HeapFree(GetProcessHeap(), 0, this_instance);
619                     return DMLERR_SYS_ERROR;
620             }
621         }
622         if ( !WaitForMutex(handle_mutex) )
623         {
624                 return DMLERR_SYS_ERROR;
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(GetProcessHeap(), 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(GetProcessHeap(), 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.@]  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.@]  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,%d,%d,%d,%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.@]
928  */
929 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
930 {
931     FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
932     return 0;
933 }
934
935 /*****************************************************************
936  * DdeQueryStringA [USER32.@]
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%x, %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.@]
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%x, %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, INT16 codepage)
1066 {
1067         FIXME("(%ld, 0x%x, %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.@]  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("(%d): 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.@)
1114  */
1115 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1116                            LPCONVCONTEXT pCC )
1117 {
1118     FIXME("(0x%lx,%d,%d,%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("(%d,%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.@)
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%x,%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.@)
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.@)
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.@]
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%x, \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.@]  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%x\n",idInst,hsz);
1380     return (BOOL)DdeFreeStringHandle( idInst, hsz );
1381 }
1382
1383
1384 /*****************************************************************
1385  *            DdeFreeStringHandle   (USER32.@)
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,%d): \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.@)
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.@)
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,%d): \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.@)
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.@)
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.@]  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,%d,%d): 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.@)
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.@)
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.@)
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.@)
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.@]  Copies data from DDE object to 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("(%d,%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.@)
1730  */
1731 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1732 {
1733      FIXME("(%d,%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.@)
1747  */
1748 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1749 {
1750      FIXME("(0x%x): 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.@)
1765  */
1766 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1767 {
1768      FIXME("(%ld, 0x%x, %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.@]  {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,%d,%d,%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(GetProcessHeap(), 0, reference_service); /* finished - release heap space used as work store */
1890                 }
1891                 DdeReleaseAtom(reference_inst,this_service->hsz);
1892                 HeapFree(GetProcessHeap(), 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( GetProcessHeap(), 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(GetProcessHeap(), 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.@]  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 INT16 WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2053 {
2054      return DdeCmpStringHandles(hsz1, hsz2);
2055 }
2056
2057 /*****************************************************************
2058  *            DdeCmpStringHandles (USER32.@)
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.@)
2124  *
2125  * RETURNS
2126  *   the packed lParam
2127  */
2128 LPARAM WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2129 {
2130     FIXME("stub.\n");
2131     return 0;
2132 }
2133
2134
2135 /*****************************************************************
2136  *            UnpackDDElParam (USER32.@)
2137  *
2138  * RETURNS
2139  *   success: nonzero
2140  *   failure: zero
2141  */
2142 BOOL WINAPI UnpackDDElParam(UINT msg, LPARAM lParam,
2143                               PUINT uiLo, PUINT uiHi)
2144 {
2145     FIXME("stub.\n");
2146     return 0;
2147 }
2148
2149
2150 /*****************************************************************
2151  *            FreeDDElParam (USER32.@)
2152  *
2153  * RETURNS
2154  *   success: nonzero
2155  *   failure: zero
2156  */
2157 BOOL WINAPI FreeDDElParam(UINT msg, LPARAM lParam)
2158 {
2159     FIXME("stub.\n");
2160     return 0;
2161 }
2162
2163 /*****************************************************************
2164  *            ReuseDDElParam (USER32.@)
2165  *
2166  * RETURNS
2167  *   the packed lParam
2168  */
2169 LPARAM WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2170                              UINT uiLi, UINT uiHi)
2171 {
2172     FIXME("stub.\n");
2173     return 0;
2174
2175
2176 /******************************************************************
2177  *              DdeQueryConvInfo16 (DDEML.9)
2178  *
2179  */
2180 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2181 {
2182         FIXME("stub.\n");
2183         return 0;
2184 }
2185
2186
2187 /******************************************************************
2188  *              DdeQueryConvInfo (USER32.@)
2189  *
2190  */
2191 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)
2192 {
2193         FIXME("stub.\n");
2194         return 0;
2195 }