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