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