Implemented reading of *.lnk-files.
[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 <strings.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
21 /* Has defined in atom.c file.
22  */
23 #define MAX_ATOM_LEN              255
24
25 /* Maximum buffer size ( including the '\0' ).
26  */
27 #define MAX_BUFFER_LEN            (MAX_ATOM_LEN + 1)
28
29
30 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
31 static LPDWORD          DDE_Max_Assigned_Instance = 0;  // OK for present, may have to worry about wrap-around later
32 static const char       inst_string[]= "DDEMaxInstance";
33 static LPCWSTR          DDEInstanceAccess = (LPCWSTR)&inst_string;
34 static const char       handle_string[] = "DDEHandleAccess";
35 static LPCWSTR          DDEHandleAccess = (LPCWSTR)&handle_string;
36 static HANDLE32         inst_count_mutex = 0;
37 static HANDLE32         handle_mutex = 0;
38        DDE_HANDLE_ENTRY *this_instance;
39        SECURITY_ATTRIBUTES *s_att= NULL;
40        DWORD            err_no = 0;
41
42 /*  typedef struct {
43         DWORD           nLength;
44         LPVOID          lpSecurityDescriptor;
45         BOOL32          bInheritHandle;
46 }       SECURITY_ATTRIBUTES; */
47
48 #define TRUE    1
49 #define FALSE   0
50
51
52
53 /* This is a simple list to keep track of the strings created
54  * by DdeCreateStringHandle.  The list is used to free
55  * the strings whenever DdeUninitialize is called.
56  * This mechanism is not complete and does not handle multiple instances.
57  * Most of the DDE API use a DWORD parameter indicating which instance
58  * of a given program is calling them.  The API are supposed to
59  * associate the data to the instance that created it.
60  */
61 typedef struct tagHSZNode HSZNode;
62 struct tagHSZNode
63 {
64     HSZNode* next;
65     HSZ hsz;
66 };
67
68 /* Start off the list pointer with a NULL.
69  */
70 static HSZNode* pHSZNodes = NULL;
71
72
73 /******************************************************************************
74  *            RemoveHSZNodes    (INTERNAL)
75  *
76  * Remove a node from the list of HSZ nodes.
77  *
78  ******************************************************************************
79  *
80  *      Change History
81  *
82  *  Vn       Date       Author                  Comment
83  *
84  *  1.0      Dec 1998  Corel/Macadamian    Initial version
85  *
86  */
87 static void RemoveHSZNode( DWORD idInst, HSZ hsz )
88 {
89     HSZNode* pPrev = NULL;
90     HSZNode* pCurrent = NULL;
91
92     /* Set the current node at the start of the list.
93      */
94     pCurrent = pHSZNodes;
95     /* While we have more nodes.
96      */
97     while( pCurrent != NULL )
98     {
99         /* If we found the node we were looking for.
100          */
101         if( pCurrent->hsz == hsz )
102         {
103             /* Remove the node.
104              */
105             /* If the first node in the list is to to be removed.
106              * Set the global list pointer to the next node.
107              */
108             if( pCurrent == pHSZNodes )
109             {
110                 pHSZNodes = pCurrent->next;
111             }
112             /* Just fix the pointers has to skip the current
113              * node so we can delete it.
114              */
115             else
116             {
117                 pPrev->next = pCurrent->next;
118             }
119             /* Destroy this node.
120              */
121             free( pCurrent );
122             break;
123         }
124         /* Save the previous node pointer.
125          */
126         pPrev = pCurrent;
127         /* Move on to the next node.
128          */
129         pCurrent = pCurrent->next;
130     }
131 }
132
133 /******************************************************************************
134  *            FreeAndRemoveHSZNodes    (INTERNAL)
135  *
136  * Frees up all the strings still allocated in the list and
137  * remove all the nodes from the list of HSZ nodes.
138  *
139  ******************************************************************************
140  *
141  *      Change History
142  *
143  *  Vn       Date       Author                  Comment
144  *
145  *  1.0      Dec 1998  Corel/Macadamian    Initial version
146  *
147  */
148 static void FreeAndRemoveHSZNodes( DWORD idInst )
149 {
150     /* Free any strings created in this instance.
151      */
152     while( pHSZNodes != NULL )
153     {
154         DdeFreeStringHandle32( idInst, pHSZNodes->hsz );
155     }
156 }
157
158 /******************************************************************************
159  *            InsertHSZNode    (INTERNAL)
160  *
161  * Insert a node to the head of the list.
162  *
163  ******************************************************************************
164  *
165  *      Change History
166  *
167  *  Vn       Date       Author                  Comment
168  *
169  *  1.0      Dec 1998  Corel/Macadamian    Initial version
170  *
171  */
172 static void InsertHSZNode( DWORD idInst, HSZ hsz )
173 {
174     if( hsz != 0 )
175     {
176         HSZNode* pNew = NULL;
177         /* Create a new node for this HSZ.
178          */
179         pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
180         if( pNew != NULL )
181         {
182             /* Set the handle value.
183              */
184             pNew->hsz = hsz;
185             /* Attach the node to the head of the list.
186              */
187             pNew->next = pHSZNodes;
188             /* The new node is now at the head of the list
189              * so set the global list pointer to it.
190              */
191             pHSZNodes = pNew;
192         }
193     }
194 }
195
196 /******************************************************************************
197  *      Release_reserved_mutex
198  *
199  *      generic routine to release a reserved mutex
200  *
201  *
202  ******************************************************************************
203  *
204  *      Change History
205  *
206  *  Vn       Date       Author                  Comment
207  *
208  *  1.0      Jan 1999  Keith Matthews        Initial version
209  *
210  */
211  DWORD Release_reserved_mutex (HANDLE32 mutex, LPTSTR mutex_name, BOOL32 release_handle_m, BOOL32 release_this_i )
212 {
213         ReleaseMutex(mutex);
214         if ( (err_no=GetLastError()) != 0 )
215         {
216                 ERR(ddeml,"ReleaseMutex failed - %s mutex %li\n",mutex_name,err_no);
217                 HeapFree(GetProcessHeap(), 0, this_instance);
218                 if ( release_handle_m )
219                 {
220                         ReleaseMutex(handle_mutex);
221                 }
222                 return DMLERR_SYS_ERROR;
223          }
224         if ( release_this_i )
225         {
226                 HeapFree(GetProcessHeap(), 0, this_instance);
227         }
228         return DMLERR_NO_ERROR;
229 }
230
231 /******************************************************************************
232  *              IncrementInstanceId
233  *
234  *      generic routine to increment the max instance Id and allocate a new application instance
235  *
236  ******************************************************************************
237  *
238  *      Change History
239  *
240  *  Vn       Date       Author                  Comment
241  *
242  *  1.0      Jan 1999  Keith Matthews        Initial version
243  *
244  */
245 DWORD IncrementInstanceId()
246 {
247         SECURITY_ATTRIBUTES s_attrib;
248         /*  Need to set up Mutex in case it is not already present */
249         // increment handle count & get value
250         if ( !inst_count_mutex )
251         {
252                 s_attrib.bInheritHandle = TRUE;
253                 s_attrib.lpSecurityDescriptor = NULL;
254                 s_attrib.nLength = sizeof(s_attrib);
255                 inst_count_mutex = CreateMutex32W(&s_attrib,1,DDEInstanceAccess); // 1st time through
256         } else {
257                 WaitForSingleObject(inst_count_mutex,1000); // subsequent calls
258                 /*  FIXME  - needs refinement with popup for timeout, also is timeout interval OK */
259         }
260         if ( (err_no=GetLastError()) == ERROR_INVALID_HANDLE )
261         {
262                 ERR(ddeml,"CreateMutex failed - inst_count %li\n",err_no);
263                 err_no=Release_reserved_mutex (handle_mutex,"handle_mutex",0,1);
264                 return DMLERR_SYS_ERROR;
265         }
266         DDE_Max_Assigned_Instance++;
267         this_instance->Instance_id = DDE_Max_Assigned_Instance;
268         if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0)) return DMLERR_SYS_ERROR;
269         return DMLERR_NO_ERROR;
270 }
271
272 /******************************************************************************
273  *            DdeInitialize16   (DDEML.2)
274  */
275 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
276                                DWORD afCmd, DWORD ulRes)
277 {
278     return (UINT16)DdeInitialize32A(pidInst,(PFNCALLBACK32)pfnCallback,
279                                     afCmd, ulRes);
280 }
281
282
283 /******************************************************************************
284  *            DdeInitialize32A   (USER32.106)
285  */
286 UINT32 WINAPI DdeInitialize32A( LPDWORD pidInst, PFNCALLBACK32 pfnCallback,
287                                 DWORD afCmd, DWORD ulRes )
288 {
289     return DdeInitialize32W(pidInst,pfnCallback,afCmd,ulRes);
290 }
291
292
293 /******************************************************************************
294  * DdeInitialize32W [USER32.107]
295  * Registers an application with the DDEML
296  *
297  * PARAMS
298  *    pidInst     [I] Pointer to instance identifier
299  *    pfnCallback [I] Pointer to callback function
300  *    afCmd       [I] Set of command and filter flags
301  *    ulRes       [I] Reserved
302  *
303  * RETURNS
304  *    Success: DMLERR_NO_ERROR
305  *    Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
306  *
307  ******************************************************************************
308  *
309  *      Change History
310  *
311  *  Vn       Date       Author                  Comment
312  *
313  *  1.0      Pre 1998  Alexandre/Len         Initial Stub
314  *  1.1      Jan 1999  Keith Matthews        Initial (near-)complete version
315  *
316  */
317 UINT32 WINAPI DdeInitialize32W( LPDWORD pidInst, PFNCALLBACK32 pfnCallback,
318                                 DWORD afCmd, DWORD ulRes )
319 {
320     DDE_HANDLE_ENTRY *reference_inst;
321     SECURITY_ATTRIBUTES s_attrib;
322     s_att = &s_attrib;
323
324 //  probably not really capable of handling mutliple processes, but should handle
325 //      multiple instances within one process
326
327     if( ulRes )
328     {
329         ERR(dde, "Reserved value not zero?  What does this mean?\n");
330         FIXME(ddeml, "(%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
331         /* trap this and no more until we know more */
332         return DMLERR_NO_ERROR;
333     }
334     if (!pfnCallback ) 
335     {
336         /* can't set up the instance with nothing to act as a callback */
337         TRACE(ddeml,"No callback provided\n");
338         return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
339      }
340
341      /* grab enough heap for one control struct - not really necessary for re-initialise
342         but allows us to use same validation routines */
343      this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( SystemHeap, 0, sizeof(DDE_HANDLE_ENTRY) );
344      if ( this_instance == NULL )
345      {
346         // catastrophe !! warn user & abort
347         ERR (ddeml,"Instance create failed - out of memory\n");
348         return DMLERR_SYS_ERROR;
349      }
350      this_instance->Next_Entry = NULL;
351      this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
352
353      // messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here
354
355      this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
356      this_instance->Instance_id = pidInst; // May need to add calling proc Id
357      this_instance->CallBack=*pfnCallback;
358      this_instance->Txn_count=0;
359      this_instance->Unicode = TRUE;
360      this_instance->Win16 = FALSE;
361      this_instance->Monitor_flags = afCmd & MF_MASK;
362
363      // isolate CBF flags in one go, expect this will go the way of all attempts to be clever !!
364
365      this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
366
367      if ( ! this_instance->Client_only )
368      {
369
370         // Check for other way of setting Client-only !!
371
372         this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
373                         ==CBF_FAIL_ALLSVRXACTIONS;
374      }
375
376      TRACE(ddeml,"instance created - checking validity \n");
377
378     if( *pidInst == 0 ) {
379         /*  Initialisation of new Instance Identifier */
380         TRACE(ddeml,"new instance, callback %p flags %lX\n",pfnCallback,afCmd);
381         /*  Need to set up Mutex in case it is not already present */
382         s_att->bInheritHandle = TRUE;
383         s_att->lpSecurityDescriptor = NULL;
384         s_att->nLength = sizeof(s_att);
385         handle_mutex = CreateMutex32W(s_att,1,DDEHandleAccess);
386         if ( (err_no=GetLastError()) == ERROR_INVALID_HANDLE )
387         {
388                 ERR(ddeml,"CreateMutex failed - handle list  %li\n",err_no);
389                 HeapFree(GetProcessHeap(), 0, this_instance);
390                 return DMLERR_SYS_ERROR;
391         }
392         TRACE(ddeml,"Handle Mutex created/reserved\n");
393         if (DDE_Handle_Table_Base == NULL ) 
394         {
395                 /* can't be another instance in this case, assign to the base pointer */
396                 DDE_Handle_Table_Base= this_instance;
397
398                 // since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
399                 //    present
400                 //   -------------------------------      NOTE NOTE NOTE    --------------------------
401                 //
402                 //         the manual is not clear if this condition
403                 //      applies to the first call to DdeInitialize from an application, or the 
404                 //      first call for a given callback !!!
405                 //
406
407                 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
408                 TRACE(ddeml,"First application instance detected OK\n");
409                 // allocate new instance ID
410                 if ((err_no = IncrementInstanceId()) ) return err_no;
411         } else {
412                 /* really need to chain the new one in to the latest here, but after checking conditions
413                 such as trying to start a conversation from an application trying to monitor */
414                 reference_inst =  DDE_Handle_Table_Base;
415                 TRACE(ddeml,"Subsequent application instance - starting checks\n");
416                 while ( reference_inst->Next_Entry != NULL ) 
417                 {
418                         //
419                         //      This set of tests will work if application uses same instance Id
420                         //      at application level once allocated - which is what manual implies
421                         //      should happen. If someone tries to be 
422                         //      clever (lazy ?) it will fail to pick up that later calls are for
423                         //      the same application - should we trust them ?
424                         //
425                         if ( this_instance->Instance_id == reference_inst->Instance_id) 
426                         {
427                                 // Check 1 - must be same Client-only state
428
429                                 if ( this_instance->Client_only != reference_inst->Client_only)
430                                 {
431                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
432                                                 return DMLERR_SYS_ERROR;
433                                         return DMLERR_DLL_USAGE;
434                                 }
435
436                                 // Check 2 - cannot use 'Monitor' with any non-monitor modes
437
438                                 if ( this_instance->Monitor != reference_inst->Monitor) 
439                                 {
440                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
441                                                 return DMLERR_SYS_ERROR;
442                                         return DMLERR_INVALIDPARAMETER;
443                                 }
444
445                                 // Check 3 - must supply different callback address
446
447                                 if ( this_instance->CallBack == reference_inst->CallBack)
448                                 {
449                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
450                                                 return DMLERR_SYS_ERROR;
451                                         return DMLERR_DLL_USAGE;
452                                 }
453                         }
454                         reference_inst = reference_inst->Next_Entry;
455                 }
456                 //  All cleared, add to chain
457
458                 TRACE(ddeml,"Application Instance checks finished\n");
459                 if ((err_no = IncrementInstanceId())) return err_no;
460                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0)) return DMLERR_SYS_ERROR;
461                 reference_inst->Next_Entry = this_instance;
462         }
463         pidInst = (LPDWORD)this_instance->Instance_id;
464         TRACE(ddeml,"New application instance processing finished OK\n");
465      } else {
466         /* Reinitialisation situation   --- FIX  */
467         TRACE(ddeml,"reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
468         WaitForSingleObject(handle_mutex,1000);
469         if ( (err_no=GetLastError()) != 0 )
470             {
471
472              /*  FIXME  - needs refinement with popup for timeout, also is timeout interval OK */
473
474                     ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
475                     HeapFree(GetProcessHeap(), 0, this_instance);
476                     return DMLERR_SYS_ERROR;
477         }
478         if (DDE_Handle_Table_Base == NULL ) 
479         {
480                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1)) return DMLERR_SYS_ERROR;
481                 return DMLERR_DLL_USAGE;
482         }
483         HeapFree(GetProcessHeap(), 0, this_instance); // finished - release heap space used as work store
484         // can't reinitialise if we have initialised nothing !!
485         reference_inst =  DDE_Handle_Table_Base;
486         /* must first check if we have been given a valid instance to re-initialise !!  how do we do that ? */
487         while ( reference_inst->Next_Entry != NULL )
488         {
489                 if ( pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
490                 {
491                         // Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY
492
493                         if (  reference_inst->Client_only )
494                         {
495                            if  ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS) 
496                            {
497                                 // i.e. Was set to Client-only and through APPCMD_CLIENTONLY
498
499                                 if ( ! ( afCmd & APPCMD_CLIENTONLY))
500                                 {
501                                         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
502                                                 return DMLERR_SYS_ERROR;
503                                         return DMLERR_DLL_USAGE;
504                                 }
505                            }
506                         }
507                         // Check 2 - cannot change monitor modes
508
509                         if ( this_instance->Monitor != reference_inst->Monitor) 
510                         {
511                                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
512                                         return DMLERR_SYS_ERROR;
513                                 return DMLERR_DLL_USAGE;
514                         }
515
516                         // Check 3 - trying to set Client-only via APPCMD when not set so previously
517
518                         if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
519                         {
520                                 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
521                                         return DMLERR_SYS_ERROR;
522                                 return DMLERR_DLL_USAGE;
523                         }
524                 }
525         }
526         //              All checked - change relevant flags
527
528         reference_inst->CBF_Flags = this_instance->CBF_Flags;
529         reference_inst->Client_only = this_instance->Client_only;
530         reference_inst->Monitor_flags = this_instance->Monitor_flags;
531         if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
532                 return DMLERR_SYS_ERROR;
533      }
534
535     return DMLERR_NO_ERROR;
536 }
537
538
539 /*****************************************************************
540  *            DdeUninitialize16   (DDEML.3)
541  */
542 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
543 {
544     return (BOOL16)DdeUninitialize32( idInst );
545 }
546
547
548 /*****************************************************************
549  * DdeUninitialize32 [USER32.119]  Frees DDEML resources
550  *
551  * PARAMS
552  *    idInst [I] Instance identifier
553  *
554  * RETURNS
555  *    Success: TRUE
556  *    Failure: FALSE
557  */
558 BOOL32 WINAPI DdeUninitialize32( DWORD idInst )
559 {
560
561     FIXME(ddeml, "(%ld): stub\n", idInst);
562
563     /* Free the nodes that were not freed by this instance
564      * and remove the nodes from the list of HSZ nodes.
565      */
566     FreeAndRemoveHSZNodes( idInst );
567     
568     return TRUE;
569 }
570
571
572 /*****************************************************************
573  * DdeConnectList16 [DDEML.4]
574  */
575 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
576                  HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
577 {
578     return DdeConnectList32(idInst, hszService, hszTopic, hConvList, 
579                             (LPCONVCONTEXT32)pCC);
580 }
581
582
583 /******************************************************************************
584  * DdeConnectList32 [USER32.93]  Establishes conversation with DDE servers
585  *
586  * PARAMS
587  *    idInst     [I] Instance identifier
588  *    hszService [I] Handle to service name string
589  *    hszTopic   [I] Handle to topic name string
590  *    hConvList  [I] Handle to conversation list
591  *    pCC        [I] Pointer to structure with context data
592  *
593  * RETURNS
594  *    Success: Handle to new conversation list
595  *    Failure: 0
596  */
597 HCONVLIST WINAPI DdeConnectList32( DWORD idInst, HSZ hszService, HSZ hszTopic,
598                  HCONVLIST hConvList, LPCONVCONTEXT32 pCC )
599 {
600     FIXME(ddeml, "(%ld,%ld,%ld,%ld,%p): stub\n", idInst, hszService, hszTopic,
601           hConvList,pCC);
602     return 1;
603 }
604
605
606 /*****************************************************************
607  * DdeQueryNextServer16 [DDEML.5]
608  */
609 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
610 {
611     return DdeQueryNextServer32(hConvList, hConvPrev);
612 }
613
614
615 /*****************************************************************
616  * DdeQueryNextServer32 [USER32.112]
617  */
618 HCONV WINAPI DdeQueryNextServer32( HCONVLIST hConvList, HCONV hConvPrev )
619 {
620     FIXME(ddeml, "(%ld,%ld): stub\n",hConvList,hConvPrev);
621     return 0;
622 }
623
624 /*****************************************************************
625  * DdeQueryString32A [USER32.113]
626  */
627 DWORD WINAPI DdeQueryString32A(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT32 iCodePage)
628 {
629     DWORD ret = 0;
630     CHAR pString[MAX_BUFFER_LEN];
631
632     FIXME(ddeml,
633          "(%ld, 0x%lx, %p, %ld, %d): stub\n",
634          idInst,
635          hsz,
636          psz, 
637          cchMax,
638          iCodePage);
639
640     if( iCodePage == CP_WINANSI )
641     {
642         /* If psz is null, we have to return only the length
643          * of the string.
644          */
645         if( psz == NULL )
646         {
647             psz = pString;
648             cchMax = MAX_BUFFER_LEN;
649 }
650
651         ret = GlobalGetAtomName32A( hsz, (LPSTR)psz, cchMax );
652     }
653     
654     return ret;
655 }
656
657 /*****************************************************************
658  * DdeQueryString32W [USER32.114]
659  */
660 DWORD WINAPI DdeQueryString32W(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT32 iCodePage)
661 {
662     DWORD ret = 0;
663     WCHAR pString[MAX_BUFFER_LEN];
664     int factor = 1;
665
666     FIXME(ddeml,
667          "(%ld, 0x%lx, %p, %ld, %d): stub\n",
668          idInst,
669          hsz,
670          psz, 
671          cchMax,
672          iCodePage);
673
674     if( iCodePage == CP_WINUNICODE )
675     {
676         /* If psz is null, we have to return only the length
677          * of the string.
678          */
679         if( psz == NULL )
680         {
681             psz = pString;
682             cchMax = MAX_BUFFER_LEN;
683             /* Note: According to documentation if the psz parameter
684              * was NULL this API must return the length of the string in bytes.
685              */
686             factor = (int) sizeof(WCHAR)/sizeof(BYTE);
687         }
688         ret = GlobalGetAtomName32W( hsz, (LPWSTR)psz, cchMax ) * factor;
689     }
690     return ret;
691 }
692
693
694 /*****************************************************************
695  *            DdeDisconnectList (DDEML.6)
696  */
697 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
698 {
699     return (BOOL16)DdeDisconnectList32(hConvList);
700 }
701
702
703 /******************************************************************************
704  * DdeDisconnectList32 [USER32.98]  Destroys list and terminates conversations
705  *
706  * RETURNS
707  *    Success: TRUE
708  *    Failure: FALSE
709  */
710 BOOL32 WINAPI DdeDisconnectList32(
711     HCONVLIST hConvList) /* [in] Handle to conversation list */
712 {
713     FIXME(ddeml, "(%ld): stub\n", hConvList);
714     return TRUE;
715 }
716
717
718 /*****************************************************************
719  *            DdeConnect16   (DDEML.7)
720  */
721 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
722                            LPCONVCONTEXT16 pCC )
723 {
724     FIXME( ddeml, "empty stub\n" );
725     return 0;
726 }
727
728
729 /*****************************************************************
730  *            DdeConnect32   (USER32.92)
731  */
732 HCONV WINAPI DdeConnect32( DWORD idInst, HSZ hszService, HSZ hszTopic,
733                            LPCONVCONTEXT32 pCC )
734 {
735     FIXME(ddeml, "(0x%lx,%ld,%ld,%p): stub\n",idInst,hszService,hszTopic,
736           pCC);
737     return 0;
738 }
739
740
741 /*****************************************************************
742  *            DdeDisconnect16   (DDEML.8)
743  */
744 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
745 {
746     return (BOOL16)DdeDisconnect32( hConv );
747 }
748
749 /*****************************************************************
750  *            DdeSetUserHandle (DDEML.10)
751  */
752 BOOL16 WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser )
753 {
754     FIXME( ddeml, "(%ld,%ld,%ld): stub\n",hConv,id, hUser );
755     return 0;
756 }
757
758 /*****************************************************************
759  *            DdeCreateDataHandle16 (DDEML.14)
760  */
761 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb, 
762                                      DWORD cbOff, HSZ hszItem, UINT16 wFmt, 
763                                      UINT16 afCmd )
764 {
765     return DdeCreateDataHandle32(idInst,
766                                 pSrc,
767                                 cb,
768                                 cbOff,
769                                 hszItem,
770                                 wFmt,
771                                 afCmd);
772 }
773
774 /*****************************************************************
775  *            DdeCreateDataHandle32 (USER32.94)
776  */
777 HDDEDATA WINAPI DdeCreateDataHandle32( DWORD idInst, LPBYTE pSrc, DWORD cb, 
778                                        DWORD cbOff, HSZ hszItem, UINT32 wFmt, 
779                                        UINT32 afCmd )
780 {
781     FIXME( ddeml,
782           "(%ld,%p,%ld,%ld,0x%lx,%d,%d): stub\n",
783           idInst,
784           pSrc,
785           cb,
786           cbOff,
787            hszItem,
788           wFmt, 
789           afCmd );
790
791     return 0;
792 }
793
794 /*****************************************************************
795  *            DdeDisconnect32   (USER32.97)
796  */
797 BOOL32 WINAPI DdeDisconnect32( HCONV hConv )
798 {
799     FIXME( ddeml, "empty stub\n" );
800     return 0;
801 }
802
803
804 /*****************************************************************
805  *            DdeReconnect   (DDEML.37) (USER32.115)
806  */
807 HCONV WINAPI DdeReconnect( HCONV hConv )
808 {
809     FIXME( ddeml, "empty stub\n" );
810     return 0;
811 }
812
813
814 /*****************************************************************
815  *            DdeCreateStringHandle16   (DDEML.21)
816  */
817 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
818 {
819     return DdeCreateStringHandle32A( idInst, str, codepage );
820 }
821
822
823 /*****************************************************************
824  * DdeCreateStringHandle32A [USER32.95]
825  *
826  * RETURNS
827  *    Success: String handle
828  *    Failure: 0
829  */
830 HSZ WINAPI DdeCreateStringHandle32A( DWORD idInst, LPCSTR psz, INT32 codepage )
831 {
832   HSZ hsz = 0;
833   TRACE(ddeml, "(%ld,%s,%d): stub\n",idInst,debugstr_a(psz),codepage);
834   
835   if (codepage==CP_WINANSI)
836   {
837       hsz = GlobalAddAtom32A (psz);
838       /* Save the handle so we know to clean it when
839        * uninitialize is called.
840        */
841       InsertHSZNode( idInst, hsz );
842       return hsz;
843   }
844     return 0;  
845 }
846
847
848 /******************************************************************************
849  * DdeCreateStringHandle32W [USER32.96]  Creates handle to identify string
850  *
851  * RETURNS
852  *    Success: String handle
853  *    Failure: 0
854  */
855 HSZ WINAPI DdeCreateStringHandle32W(
856     DWORD idInst,   /* [in] Instance identifier */
857     LPCWSTR psz,    /* [in] Pointer to string */
858     INT32 codepage) /* [in] Code page identifier */
859 {
860   HSZ hsz = 0;
861
862     FIXME(ddeml, "(%ld,%s,%d): stub\n",idInst,debugstr_w(psz),codepage);
863
864   if (codepage==CP_WINUNICODE)
865   {
866       hsz = GlobalAddAtom32W (psz);
867       /* Save the handle so we know to clean it when
868        * uninitialize is called.
869        */
870       InsertHSZNode( idInst, hsz );
871       return hsz;
872 }
873   return 0;
874 }
875
876
877 /*****************************************************************
878  *            DdeFreeStringHandle16   (DDEML.22)
879  */
880 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
881 {
882     return (BOOL32)DdeFreeStringHandle32( idInst, hsz );
883 }
884
885
886 /*****************************************************************
887  *            DdeFreeStringHandle32   (USER32.101)
888  * RETURNS: success: nonzero
889  *          fail:    zero
890  */
891 BOOL32 WINAPI DdeFreeStringHandle32( DWORD idInst, HSZ hsz )
892 {
893     TRACE( ddeml, "(%ld,%ld): stub\n",idInst, hsz );
894     /* Remove the node associated with this HSZ.
895      */
896     RemoveHSZNode( idInst, hsz );
897     /* Free the string associated with this HSZ.
898      */
899     return GlobalDeleteAtom (hsz) ? 0 : hsz;
900 }
901
902
903 /*****************************************************************
904  *            DdeFreeDataHandle16   (DDEML.19)
905  */
906 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
907 {
908     return (BOOL32)DdeFreeDataHandle32( hData );
909 }
910
911
912 /*****************************************************************
913  *            DdeFreeDataHandle32   (USER32.100)
914  */
915 BOOL32 WINAPI DdeFreeDataHandle32( HDDEDATA hData )
916 {
917     FIXME( ddeml, "empty stub\n" );
918     return TRUE;
919 }
920
921
922
923
924 /*****************************************************************
925  *            DdeKeepStringHandle16   (DDEML.24)
926  */
927 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
928 {
929     return (BOOL32)DdeKeepStringHandle32( idInst, hsz );
930 }
931
932
933 /*****************************************************************
934  *            DdeKeepStringHandle32  (USER32.108)
935  */
936 BOOL32 WINAPI DdeKeepStringHandle32( DWORD idInst, HSZ hsz )
937 {
938     FIXME( ddeml, "empty stub\n" );
939     return TRUE;
940 }
941
942
943 /*****************************************************************
944  *            DdeClientTransaction16  (DDEML.11)
945  */
946 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
947                                         HCONV hConv, HSZ hszItem, UINT16 wFmt,
948                                         UINT16 wType, DWORD dwTimeout,
949                                         LPDWORD pdwResult )
950 {
951     return DdeClientTransaction32( (LPBYTE)pData, cbData, hConv, hszItem,
952                                    wFmt, wType, dwTimeout, pdwResult );
953 }
954
955
956 /*****************************************************************
957  *            DdeClientTransaction32  (USER32.90)
958  */
959 HDDEDATA WINAPI DdeClientTransaction32( LPBYTE pData, DWORD cbData,
960                                         HCONV hConv, HSZ hszItem, UINT32 wFmt,
961                                         UINT32 wType, DWORD dwTimeout,
962                                         LPDWORD pdwResult )
963 {
964     FIXME( ddeml, "empty stub\n" );
965     return 0;
966 }
967
968 /*****************************************************************
969  *            DdeAbandonTransaction (DDEML.12)
970  */
971 BOOL16 WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv, 
972                                      DWORD idTransaction )
973 {
974     FIXME( ddeml, "empty stub\n" );
975     return 0;
976 }
977
978
979 /*****************************************************************
980  * DdePostAdvise16 [DDEML.13]
981  */
982 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
983 {
984     return (BOOL16)DdePostAdvise32(idInst, hszTopic, hszItem);
985 }
986
987
988 /******************************************************************************
989  * DdePostAdvise32 [USER32.110]  Send transaction to DDE callback function.
990  *
991  * RETURNS
992  *    Success: TRUE
993  *    Failure: FALSE
994  */
995 BOOL32 WINAPI DdePostAdvise32(
996     DWORD idInst, /* [in] Instance identifier */
997     HSZ hszTopic, /* [in] Handle to topic name string */
998     HSZ hszItem)  /* [in] Handle to item name string */
999 {
1000     FIXME(ddeml, "(%ld,%ld,%ld): stub\n",idInst,hszTopic,hszItem);
1001     return TRUE;
1002 }
1003
1004
1005 /*****************************************************************
1006  *            DdeAddData (DDEML.15)
1007  */
1008 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1009                             DWORD cbOff )
1010 {
1011     FIXME( ddeml, "empty stub\n" );
1012     return 0;
1013 }
1014
1015
1016 /******************************************************************************
1017  * DdeGetData32 [USER32.102]  Copies data from DDE object ot local buffer
1018  *
1019  * RETURNS
1020  *    Size of memory object associated with handle
1021  */
1022 DWORD WINAPI DdeGetData32(
1023     HDDEDATA hData, /* [in] Handle to DDE object */
1024     LPBYTE pDst,    /* [in] Pointer to destination buffer */
1025     DWORD cbMax,    /* [in] Amount of data to copy */
1026     DWORD cbOff)    /* [in] Offset to beginning of data */
1027 {
1028     FIXME(ddeml, "(%ld,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1029     return cbMax;
1030 }
1031
1032
1033 /*****************************************************************
1034  * DdeGetData16 [DDEML.16]
1035  */
1036 DWORD WINAPI DdeGetData16(
1037     HDDEDATA hData,
1038     LPBYTE pDst,
1039     DWORD cbMax, 
1040     DWORD cbOff)
1041 {
1042     return DdeGetData32(hData, pDst, cbMax, cbOff);
1043 }
1044
1045
1046 /*****************************************************************
1047  *            DdeAccessData16 (DDEML.17)
1048  */
1049 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1050 {
1051      return DdeAccessData32(hData, pcbDataSize);
1052 }
1053
1054 /*****************************************************************
1055  *            DdeAccessData32 (USER32.88)
1056  */
1057 LPBYTE WINAPI DdeAccessData32( HDDEDATA hData, LPDWORD pcbDataSize )
1058 {
1059      FIXME( ddeml, "(%ld,%p): stub\n", hData, pcbDataSize);
1060      return 0;
1061 }
1062
1063 /*****************************************************************
1064  *            DdeUnaccessData16 (DDEML.18)
1065  */
1066 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1067 {
1068      return DdeUnaccessData32(hData);
1069 }
1070
1071 /*****************************************************************
1072  *            DdeUnaccessData32 (USER32.118)
1073  */
1074 BOOL32 WINAPI DdeUnaccessData32( HDDEDATA hData )
1075 {
1076      FIXME( ddeml, "(0x%lx): stub\n", hData);
1077
1078      return 0;
1079 }
1080
1081 /*****************************************************************
1082  *            DdeEnableCallback16 (DDEML.26)
1083  */
1084 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1085 {
1086      return DdeEnableCallback32(idInst, hConv, wCmd);
1087 }
1088
1089 /*****************************************************************
1090  *            DdeEnableCallback32 (USER32.99)
1091  */
1092 BOOL32 WINAPI DdeEnableCallback32( DWORD idInst, HCONV hConv, UINT32 wCmd )
1093 {
1094      FIXME( ddeml, "(%ld, 0x%lx, %d) stub\n", idInst, hConv, wCmd);
1095
1096      return 0;
1097 }
1098
1099 /*****************************************************************
1100  *            DdeNameService16  (DDEML.27)
1101  */
1102 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1103                                   UINT16 afCmd )
1104 {
1105     return DdeNameService32( idInst, hsz1, hsz2, afCmd );
1106 }
1107
1108
1109 /******************************************************************************
1110  * DdeNameService32 [USER32.109]  {Un}registers service name of DDE server
1111  *
1112  * PARAMS
1113  *    idInst [I] Instance identifier
1114  *    hsz1   [I] Handle to service name string
1115  *    hsz2   [I] Reserved
1116  *    afCmd  [I] Service name flags
1117  *
1118  * RETURNS
1119  *    Success: Non-zero
1120  *    Failure: 0
1121  */
1122 HDDEDATA WINAPI DdeNameService32( DWORD idInst, HSZ hsz1, HSZ hsz2,
1123                 UINT32 afCmd )
1124 {
1125     FIXME(ddeml, "(%ld,%ld,%ld,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1126     return 1;
1127 }
1128
1129
1130 /*****************************************************************
1131  *            DdeGetLastError16  (DDEML.20)
1132  */
1133 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1134 {
1135     return (UINT16)DdeGetLastError32( idInst );
1136 }
1137
1138
1139 /******************************************************************************
1140  * DdeGetLastError32 [USER32.103]  Gets most recent error code
1141  *
1142  * PARAMS
1143  *    idInst [I] Instance identifier
1144  *
1145  * RETURNS
1146  *    Last error code
1147  */
1148 UINT32 WINAPI DdeGetLastError32( DWORD idInst )
1149 {
1150     FIXME(ddeml, "(%ld): stub\n",idInst);
1151     return 0;
1152 }
1153
1154
1155 /*****************************************************************
1156  *            DdeCmpStringHandles16 (DDEML.36)
1157  */
1158 int WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
1159 {
1160      return DdeCmpStringHandles32(hsz1, hsz2);
1161 }
1162
1163 /*****************************************************************
1164  *            DdeCmpStringHandles32 (USER32.91)
1165  *
1166  * Compares the value of two string handles.  This comparison is
1167  * not case sensitive.
1168  *
1169  * Returns:
1170  * -1 The value of hsz1 is zero or less than hsz2
1171  * 0  The values of hsz 1 and 2 are the same or both zero.
1172  * 1  The value of hsz2 is zero of less than hsz1
1173  */
1174 int WINAPI DdeCmpStringHandles32( HSZ hsz1, HSZ hsz2 )
1175 {
1176     CHAR psz1[MAX_BUFFER_LEN];
1177     CHAR psz2[MAX_BUFFER_LEN];
1178     int ret = 0;
1179     int ret1, ret2;
1180
1181     TRACE( ddeml, "handle 1, handle 2\n" );
1182
1183     ret1 = GlobalGetAtomName32A( hsz1, psz1, MAX_BUFFER_LEN );
1184     ret2 = GlobalGetAtomName32A( hsz2, psz2, MAX_BUFFER_LEN );
1185     /* Make sure we found both strings.
1186      */
1187     if( ret1 == 0 && ret2 == 0 )
1188     {
1189         /* If both are not found, return both  "zero strings".
1190          */
1191         ret = 0;
1192     }
1193     else if( ret1 == 0 )
1194     {
1195         /* If hsz1 is a not found, return hsz1 is "zero string".
1196          */
1197         ret = -1;
1198     }
1199     else if( ret2 == 0 )
1200     {
1201         /* If hsz2 is a not found, return hsz2 is "zero string".
1202          */
1203         ret = 1;
1204     }
1205     else
1206     {
1207         /* Compare the two strings we got ( case insensitive ).
1208          */
1209         ret = strcasecmp( psz1, psz2 );
1210         /* Since strcmp returns any number smaller than
1211          * 0 when the first string is found to be less than
1212          * the second one we must make sure we are returning
1213          * the proper values.
1214          */
1215         if( ret < 0 )
1216         {
1217             ret = -1;
1218         }
1219         else if( ret > 0 )
1220         {
1221             ret = 1;
1222         }
1223     }
1224
1225     return ret;
1226 }
1227
1228 /*****************************************************************
1229  *            PackDDElParam (USER32.414)
1230  *
1231  * RETURNS
1232  *   success: nonzero
1233  *   failure: zero
1234  */
1235 UINT32 WINAPI PackDDElParam(UINT32 msg, UINT32 uiLo, UINT32 uiHi)
1236 {
1237     FIXME(ddeml, "stub.\n");
1238     return 0;
1239 }
1240
1241
1242 /*****************************************************************
1243  *            UnpackDDElParam (USER32.562)
1244  *
1245  * RETURNS
1246  *   success: nonzero
1247  *   failure: zero
1248  */
1249 UINT32 WINAPI UnpackDDElParam(UINT32 msg, UINT32 lParam,
1250                               UINT32 *uiLo, UINT32 *uiHi)
1251 {
1252     FIXME(ddeml, "stub.\n");
1253     return 0;
1254 }
1255
1256
1257 /*****************************************************************
1258  *            FreeDDElParam (USER32.204)
1259  *
1260  * RETURNS
1261  *   success: nonzero
1262  *   failure: zero
1263  */
1264 UINT32 WINAPI FreeDDElParam(UINT32 msg, UINT32 lParam)
1265 {
1266     FIXME(ddeml, "stub.\n");
1267     return 0;
1268 }
1269
1270 /*****************************************************************
1271  *            ReuseDDElParam (USER32.446)
1272  *
1273  */
1274 UINT32 WINAPI ReuseDDElParam(UINT32 lParam, UINT32 msgIn, UINT32 msgOut,
1275                              UINT32 uiLi, UINT32 uiHi)
1276 {
1277     FIXME(ddeml, "stub.\n");
1278     return 0;
1279