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