Moved .spec files to corresponding dlls/ directory.
[wine/testsucceed.git] / misc / ddeml.c
blob1dd3407249cf40291e4606f4a1a9a9156d7066be
1 /*
2 * DDEML library
4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Len White
6 * Copyright 1999 Keith Matthews
7 */
9 /* Only empty stubs for now */
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 "debugtools.h"
19 #include "tchar.h"
20 #include "winnt.h"
22 DEFAULT_DEBUG_CHANNEL(ddeml)
24 /* Has defined in atom.c file.
26 #define MAX_ATOM_LEN 255
28 /* Maximum buffer size ( including the '\0' ).
30 #define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1)
32 /* typedef struct {
33 DWORD nLength;
34 LPVOID lpSecurityDescriptor;
35 BOOL bInheritHandle;
36 } SECURITY_ATTRIBUTES; */
38 /* This is a simple list to keep track of the strings created
39 * by DdeCreateStringHandle. The list is used to free
40 * the strings whenever DdeUninitialize is called.
41 * This mechanism is not complete and does not handle multiple instances.
42 * Most of the DDE API use a DWORD parameter indicating which instance
43 * of a given program is calling them. The API are supposed to
44 * associate the data to the instance that created it.
46 typedef struct tagHSZNode HSZNode;
47 struct tagHSZNode
49 HSZNode* next;
50 HSZ hsz;
54 typedef struct tagServiceNode ServiceNode;
55 struct tagServiceNode
57 ServiceNode* next;
58 HSZ hsz;
59 BOOL16 FilterOn;
61 typedef struct DDE_HANDLE_ENTRY {
62 BOOL16 Monitor; /* have these two as full Booleans cos they'll be tested frequently */
63 BOOL16 Client_only; /* bit wasteful of space but it will be faster */
64 BOOL16 Unicode; /* Flag to indicate Win32 API used to initialise */
65 BOOL16 Win16; /* flag to indicate Win16 API used to initialize */
66 DWORD Instance_id; /* needed to track monitor usage */
67 struct DDE_HANDLE_ENTRY *Next_Entry;
68 HSZNode *Node_list;
69 PFNCALLBACK CallBack;
70 DWORD CBF_Flags;
71 DWORD Monitor_flags;
72 UINT Txn_count; /* count transactions open to simplify closure */
73 DWORD Last_Error;
74 ServiceNode* ServiceNames;
75 } DDE_HANDLE_ENTRY;
77 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
78 static DWORD DDE_Max_Assigned_Instance = 0; /* OK for present, may have to worry about wrap-around later */
79 static const char inst_string[]= "DDEMaxInstance";
80 static LPCWSTR DDEInstanceAccess = (LPCWSTR)&inst_string;
81 static const char handle_string[] = "DDEHandleAccess";
82 static LPCWSTR DDEHandleAccess = (LPCWSTR)&handle_string;
83 static HANDLE inst_count_mutex = 0;
84 static HANDLE handle_mutex = 0;
86 #define TRUE 1
87 #define FALSE 0
90 /******************************************************************************
91 * RemoveHSZNodes (INTERNAL)
93 * Remove a node from the list of HSZ nodes.
95 ******************************************************************************
97 * Change History
99 * Vn Date Author Comment
101 * 1.0 Dec 1998 Corel/Macadamian Initial version
102 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
105 static void RemoveHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
107 HSZNode* pPrev = NULL;
108 HSZNode* pCurrent = NULL;
110 /* Set the current node at the start of the list.
112 pCurrent = reference_inst->Node_list;
113 /* While we have more nodes.
115 while( pCurrent != NULL )
117 /* If we found the node we were looking for.
119 if( pCurrent->hsz == hsz )
121 /* Remove the node.
123 /* If the first node in the list is to to be removed.
124 * Set the global list pointer to the next node.
126 if( pCurrent == reference_inst->Node_list )
128 reference_inst->Node_list = pCurrent->next;
130 /* Just fix the pointers has to skip the current
131 * node so we can delete it.
133 else
135 pPrev->next = pCurrent->next;
137 /* Destroy this node.
139 free( pCurrent );
140 break;
142 /* Save the previous node pointer.
144 pPrev = pCurrent;
145 /* Move on to the next node.
147 pCurrent = pCurrent->next;
151 /******************************************************************************
152 * FreeAndRemoveHSZNodes (INTERNAL)
154 * Frees up all the strings still allocated in the list and
155 * remove all the nodes from the list of HSZ nodes.
157 ******************************************************************************
159 * Change History
161 * Vn Date Author Comment
163 * 1.0 Dec 1998 Corel/Macadamian Initial version
164 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
167 static void FreeAndRemoveHSZNodes( DWORD idInst, DDE_HANDLE_ENTRY * reference_inst )
169 /* Free any strings created in this instance.
171 while( reference_inst->Node_list != NULL )
173 DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
177 /******************************************************************************
178 * InsertHSZNode (INTERNAL)
180 * Insert a node to the head of the list.
182 ******************************************************************************
184 * Change History
186 * Vn Date Author Comment
188 * 1.0 Dec 1998 Corel/Macadamian Initial version
189 * 1.1 Mar 1999 Keith Matthews Added instance handling
190 * 1.2 Jun 1999 Keith Matthews Added Usage count handling
193 static void InsertHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
195 if( hsz != 0 )
197 HSZNode* pNew = NULL;
198 /* Create a new node for this HSZ.
200 pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
201 if( pNew != NULL )
203 /* Set the handle value.
205 pNew->hsz = hsz;
206 /* Attach the node to the head of the list. i.e most recently added is first
208 pNew->next = reference_inst->Node_list;
210 /* The new node is now at the head of the list
211 * so set the global list pointer to it.
213 reference_inst->Node_list = pNew;
214 TRACE("HSZ node list entry added\n");
219 /*****************************************************************************
220 * Find_Instance_Entry
222 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
223 * for an instance Id, or NULL if the entry does not exist
225 * ASSUMES the mutex protecting the handle entry list is reserved before calling
227 ******************************************************************************
229 * Change History
231 * Vn Date Author Comment
233 * 1.0 March 1999 Keith Matthews 1st implementation
235 DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
237 DDE_HANDLE_ENTRY * reference_inst;
238 reference_inst = DDE_Handle_Table_Base;
239 while ( reference_inst != NULL )
241 if ( reference_inst->Instance_id == InstId )
243 TRACE("Instance entry found\n");
244 return reference_inst;
246 reference_inst = reference_inst->Next_Entry;
248 TRACE("Instance entry missing\n");
249 return NULL;
252 /*****************************************************************************
253 * Find_Service_Name
255 * generic routine to return a pointer to the relevant ServiceNode
256 * for a given service name, or NULL if the entry does not exist
258 * ASSUMES the mutex protecting the handle entry list is reserved before calling
260 ******************************************************************************
262 * Change History
264 * Vn Date Author Comment
266 * 1.0 May 1999 Keith Matthews 1st implementation
268 ServiceNode *Find_Service_Name (HSZ Service_Name, DDE_HANDLE_ENTRY* this_instance)
270 ServiceNode * reference_name= this_instance->ServiceNames;
271 while ( reference_name != NULL )
273 if ( reference_name->hsz == Service_Name )
275 TRACE("Service Name found\n");
276 return reference_name;
278 reference_name = reference_name->next;
280 TRACE("Service name missing\n");
281 return NULL;
285 /******************************************************************************
286 * Release_reserved_mutex
288 * generic routine to release a reserved mutex
291 ******************************************************************************
293 * Change History
295 * Vn Date Author Comment
297 * 1.0 Jan 1999 Keith Matthews Initial version
298 * 1.1 Mar 1999 Keith Matthews Corrected Heap handling. Corrected re-initialisation handling
301 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i ,
302 DDE_HANDLE_ENTRY *this_instance)
304 DWORD err_no = 0;
305 ReleaseMutex(mutex);
306 if ( (err_no=GetLastError()) != 0 )
308 ERR("ReleaseMutex failed - %s mutex %li\n",mutex_name,err_no);
309 HeapFree(SystemHeap, 0, this_instance);
310 if ( release_handle_m )
312 ReleaseMutex(handle_mutex);
314 return DMLERR_SYS_ERROR;
316 if ( release_this_i )
318 HeapFree(SystemHeap, 0, this_instance);
320 return DMLERR_NO_ERROR;
323 /******************************************************************************
324 * IncrementInstanceId
326 * generic routine to increment the max instance Id and allocate a new application instance
328 ******************************************************************************
330 * Change History
332 * Vn Date Author Comment
334 * 1.0 Jan 1999 Keith Matthews Initial version
337 DWORD IncrementInstanceId( DDE_HANDLE_ENTRY *this_instance)
339 SECURITY_ATTRIBUTES s_attrib;
340 DWORD err_no = 0;
341 /* Need to set up Mutex in case it is not already present */
342 /* increment handle count & get value */
343 if ( !inst_count_mutex )
345 s_attrib.bInheritHandle = TRUE;
346 s_attrib.lpSecurityDescriptor = NULL;
347 s_attrib.nLength = sizeof(s_attrib);
348 inst_count_mutex = CreateMutexW(&s_attrib,1,DDEInstanceAccess); /* 1st time through */
349 } else {
350 WaitForSingleObject(inst_count_mutex,1000); /* subsequent calls */
351 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
353 if ( (err_no=GetLastError()) != 0 )
355 ERR("CreateMutex failed - inst_count %li\n",err_no);
356 err_no=Release_reserved_mutex (handle_mutex,"handle_mutex",0,1,this_instance);
357 return DMLERR_SYS_ERROR;
359 DDE_Max_Assigned_Instance++;
360 this_instance->Instance_id = DDE_Max_Assigned_Instance;
361 TRACE("New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
362 if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0,this_instance)) return DMLERR_SYS_ERROR;
363 return DMLERR_NO_ERROR;
366 /******************************************************************************
367 * FindNotifyMonitorCallbacks
369 * Routine to find instances that need to be notified via their callback
370 * of some event they are monitoring
372 ******************************************************************************
374 * Change History
376 * Vn Date Author Comment
378 * 1.0 May 1999 Keith Matthews Initial Version
382 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
384 DDE_HANDLE_ENTRY *InstanceHandle;
385 InstanceHandle = DDE_Handle_Table_Base;
386 while ( InstanceHandle != NULL )
388 if ( (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
390 /* Found an instance registered as monitor and is not ourselves
391 * use callback to notify where appropriate
394 InstanceHandle = InstanceHandle->Next_Entry;
398 /******************************************************************************
399 * DdeReserveAtom
401 * Routine to make an extra Add on an atom to reserve it a bit longer
403 ******************************************************************************
405 * Change History
407 * Vn Date Author Comment
409 * 1.0 Jun 1999 Keith Matthews Initial Version
413 void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
415 CHAR SNameBuffer[MAX_BUFFER_LEN];
416 UINT rcode;
417 if ( reference_inst->Unicode)
419 rcode=GlobalGetAtomNameW(hsz,(LPWSTR)&SNameBuffer,MAX_ATOM_LEN);
420 GlobalAddAtomW((LPWSTR)SNameBuffer);
421 } else {
422 rcode=GlobalGetAtomNameA(hsz,SNameBuffer,MAX_ATOM_LEN);
423 GlobalAddAtomA(SNameBuffer);
428 /******************************************************************************
429 * DdeReleaseAtom
431 * Routine to make a delete on an atom to release it a bit sooner
433 ******************************************************************************
435 * Change History
437 * Vn Date Author Comment
439 * 1.0 Jun 1999 Keith Matthews Initial Version
443 void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
445 CHAR SNameBuffer[MAX_BUFFER_LEN];
446 UINT rcode;
447 if ( reference_inst->Unicode)
449 rcode=GlobalGetAtomNameW(hsz,(LPWSTR)&SNameBuffer,MAX_ATOM_LEN);
450 GlobalAddAtomW((LPWSTR)SNameBuffer);
451 } else {
452 rcode=GlobalGetAtomNameA(hsz,SNameBuffer,MAX_ATOM_LEN);
453 GlobalAddAtomA(SNameBuffer);
457 /******************************************************************************
458 * DdeInitialize16 (DDEML.2)
460 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
461 DWORD afCmd, DWORD ulRes)
463 TRACE("DdeInitialize16 called - calling DdeInitializeA\n");
464 return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
465 afCmd, ulRes);
469 /******************************************************************************
470 * DdeInitializeA (USER32.106)
472 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
473 DWORD afCmd, DWORD ulRes )
475 TRACE("DdeInitializeA called - calling DdeInitializeW\n");
476 return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
480 /******************************************************************************
481 * DdeInitializeW [USER32.107]
482 * Registers an application with the DDEML
484 * PARAMS
485 * pidInst [I] Pointer to instance identifier
486 * pfnCallback [I] Pointer to callback function
487 * afCmd [I] Set of command and filter flags
488 * ulRes [I] Reserved
490 * RETURNS
491 * Success: DMLERR_NO_ERROR
492 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
494 ******************************************************************************
496 * Change History
498 * Vn Date Author Comment
500 * 1.0 Pre 1998 Alexandre/Len Initial Stub
501 * 1.1 Jan 1999 Keith Matthews Initial (near-)complete version
502 * 1.2 Mar 1999 Keith Matthews Corrected Heap handling, CreateMutex failure handling
505 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
506 DWORD afCmd, DWORD ulRes )
509 /* probably not really capable of handling mutliple processes, but should handle
510 * multiple instances within one process */
512 SECURITY_ATTRIBUTES *s_att= NULL;
513 SECURITY_ATTRIBUTES s_attrib;
514 DWORD err_no = 0;
515 DDE_HANDLE_ENTRY *this_instance;
516 DDE_HANDLE_ENTRY *reference_inst;
517 s_att = &s_attrib;
519 if( ulRes )
521 ERR("Reserved value not zero? What does this mean?\n");
522 FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
523 afCmd,ulRes);
524 /* trap this and no more until we know more */
525 return DMLERR_NO_ERROR;
527 if (!pfnCallback )
529 /* this one may be wrong - MS dll seems to accept the condition,
530 leave this until we find out more !! */
533 /* can't set up the instance with nothing to act as a callback */
534 TRACE("No callback provided\n");
535 return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
538 /* grab enough heap for one control struct - not really necessary for re-initialise
539 * but allows us to use same validation routines */
540 this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( SystemHeap, 0, sizeof(DDE_HANDLE_ENTRY) );
541 if ( this_instance == NULL )
543 /* catastrophe !! warn user & abort */
544 ERR("Instance create failed - out of memory\n");
545 return DMLERR_SYS_ERROR;
547 this_instance->Next_Entry = NULL;
548 this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
550 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
552 this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
553 this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
554 this_instance->CallBack=*pfnCallback;
555 this_instance->Txn_count=0;
556 this_instance->Unicode = TRUE;
557 this_instance->Win16 = FALSE;
558 this_instance->Node_list = NULL; /* node will be added later */
559 this_instance->Monitor_flags = afCmd & MF_MASK;
560 this_instance->ServiceNames = NULL;
562 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
564 this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
566 if ( ! this_instance->Client_only )
569 /* Check for other way of setting Client-only !! */
571 this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
572 ==CBF_FAIL_ALLSVRXACTIONS;
575 TRACE("instance created - checking validity \n");
577 if( *pidInst == 0 ) {
578 /* Initialisation of new Instance Identifier */
579 TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
580 if ( DDE_Max_Assigned_Instance == 0 )
582 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
583 /* Need to set up Mutex in case it is not already present */
584 s_att->bInheritHandle = TRUE;
585 s_att->lpSecurityDescriptor = NULL;
586 s_att->nLength = sizeof(s_att);
587 handle_mutex = CreateMutexW(s_att,1,DDEHandleAccess);
588 if ( (err_no=GetLastError()) != 0 )
590 ERR("CreateMutex failed - handle list %li\n",err_no);
591 HeapFree(SystemHeap, 0, this_instance);
592 return DMLERR_SYS_ERROR;
594 } else
596 WaitForSingleObject(handle_mutex,1000);
597 if ( (err_no=GetLastError()) != 0 )
599 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
601 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
602 return DMLERR_SYS_ERROR;
606 TRACE("Handle Mutex created/reserved\n");
607 if (DDE_Handle_Table_Base == NULL )
609 /* can't be another instance in this case, assign to the base pointer */
610 DDE_Handle_Table_Base= this_instance;
612 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
613 * present
614 * ------------------------------- NOTE NOTE NOTE --------------------------
616 * the manual is not clear if this condition
617 * applies to the first call to DdeInitialize from an application, or the
618 * first call for a given callback !!!
621 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
622 TRACE("First application instance detected OK\n");
623 /* allocate new instance ID */
624 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
626 } else {
627 /* really need to chain the new one in to the latest here, but after checking conditions
628 * such as trying to start a conversation from an application trying to monitor */
629 reference_inst = DDE_Handle_Table_Base;
630 TRACE("Subsequent application instance - starting checks\n");
631 while ( reference_inst->Next_Entry != NULL )
634 * This set of tests will work if application uses same instance Id
635 * at application level once allocated - which is what manual implies
636 * should happen. If someone tries to be
637 * clever (lazy ?) it will fail to pick up that later calls are for
638 * the same application - should we trust them ?
640 if ( this_instance->Instance_id == reference_inst->Instance_id)
642 /* Check 1 - must be same Client-only state */
644 if ( this_instance->Client_only != reference_inst->Client_only)
646 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
647 return DMLERR_SYS_ERROR;
648 return DMLERR_DLL_USAGE;
651 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
653 if ( this_instance->Monitor != reference_inst->Monitor)
655 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
656 return DMLERR_SYS_ERROR;
657 return DMLERR_INVALIDPARAMETER;
660 /* Check 3 - must supply different callback address */
662 if ( this_instance->CallBack == reference_inst->CallBack)
664 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
665 return DMLERR_SYS_ERROR;
666 return DMLERR_DLL_USAGE;
669 reference_inst = reference_inst->Next_Entry;
671 /* All cleared, add to chain */
673 TRACE("Application Instance checks finished\n");
674 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
675 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0,this_instance)) return DMLERR_SYS_ERROR;
676 reference_inst->Next_Entry = this_instance;
678 *pidInst = this_instance->Instance_id;
679 TRACE("New application instance processing finished OK\n");
680 } else {
681 /* Reinitialisation situation --- FIX */
682 TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
683 WaitForSingleObject(handle_mutex,1000);
684 if ( (err_no=GetLastError()) != 0 )
687 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
689 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
690 HeapFree(SystemHeap, 0, this_instance);
691 return DMLERR_SYS_ERROR;
693 if (DDE_Handle_Table_Base == NULL )
695 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance)) return DMLERR_SYS_ERROR;
696 return DMLERR_DLL_USAGE;
698 HeapFree(SystemHeap, 0, this_instance); /* finished - release heap space used as work store */
699 /* can't reinitialise if we have initialised nothing !! */
700 reference_inst = DDE_Handle_Table_Base;
701 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
703 * MS allows initialisation without specifying a callback, should we allow addition of the
704 * callback by a later call to initialise ? - if so this lot will have to change
706 while ( reference_inst->Next_Entry != NULL )
708 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
710 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
712 if ( reference_inst->Client_only )
714 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
716 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
718 if ( ! ( afCmd & APPCMD_CLIENTONLY))
720 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
721 return DMLERR_SYS_ERROR;
722 return DMLERR_DLL_USAGE;
726 /* Check 2 - cannot change monitor modes */
728 if ( this_instance->Monitor != reference_inst->Monitor)
730 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
731 return DMLERR_SYS_ERROR;
732 return DMLERR_DLL_USAGE;
735 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
737 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
739 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
740 return DMLERR_SYS_ERROR;
741 return DMLERR_DLL_USAGE;
743 break;
745 reference_inst = reference_inst->Next_Entry;
747 if ( reference_inst->Next_Entry == NULL )
749 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
751 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
753 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
754 return DMLERR_SYS_ERROR;
755 return DMLERR_INVALIDPARAMETER;
757 /* All checked - change relevant flags */
759 reference_inst->CBF_Flags = this_instance->CBF_Flags;
760 reference_inst->Client_only = this_instance->Client_only;
761 reference_inst->Monitor_flags = this_instance->Monitor_flags;
762 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
763 return DMLERR_SYS_ERROR;
766 return DMLERR_NO_ERROR;
770 /*****************************************************************
771 * DdeUninitialize16 (DDEML.3)
773 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
775 FIXME(" stub calling DdeUninitialize\n");
776 return (BOOL16)DdeUninitialize( idInst );
780 /*****************************************************************
781 * DdeUninitialize [USER32.119] Frees DDEML resources
783 * PARAMS
784 * idInst [I] Instance identifier
786 * RETURNS
787 * Success: TRUE
788 * Failure: FALSE
791 BOOL WINAPI DdeUninitialize( DWORD idInst )
793 /* Stage one - check if we have a handle for this instance
795 DWORD err_no = 0;
796 SECURITY_ATTRIBUTES *s_att= NULL;
797 SECURITY_ATTRIBUTES s_attrib;
798 DDE_HANDLE_ENTRY *this_instance;
799 DDE_HANDLE_ENTRY *reference_inst;
800 s_att = &s_attrib;
802 if ( DDE_Max_Assigned_Instance == 0 )
804 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
805 return TRUE;
807 WaitForSingleObject(handle_mutex,1000);
808 if ( (err_no=GetLastError()) != 0 )
810 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
812 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
813 return DMLERR_SYS_ERROR;
815 TRACE("Handle Mutex created/reserved\n");
816 /* First check instance
818 this_instance = Find_Instance_Entry(idInst);
819 if ( this_instance == NULL )
821 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return FALSE;
823 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
825 return FALSE;
827 FIXME("(%ld): partial stub\n", idInst);
829 /* FIXME ++++++++++++++++++++++++++++++++++++++++++
830 * Needs to de-register all service names
833 /* Free the nodes that were not freed by this instance
834 * and remove the nodes from the list of HSZ nodes.
836 FreeAndRemoveHSZNodes( idInst, this_instance );
838 /* OK now delete the instance handle itself */
840 if ( DDE_Handle_Table_Base == this_instance )
842 /* special case - the first/only entry
844 DDE_Handle_Table_Base = this_instance->Next_Entry;
845 } else
847 /* general case
849 reference_inst = DDE_Handle_Table_Base;
850 while ( reference_inst->Next_Entry != this_instance )
852 reference_inst = this_instance->Next_Entry;
854 reference_inst->Next_Entry = this_instance->Next_Entry;
856 /* release the mutex and the heap entry
858 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE,this_instance))
860 /* should record something here, but nothing left to hang it from !!
862 return FALSE;
864 return TRUE;
868 /*****************************************************************
869 * DdeConnectList16 [DDEML.4]
872 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
873 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
875 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
876 (LPCONVCONTEXT)pCC);
880 /******************************************************************************
881 * DdeConnectList [USER32.93] Establishes conversation with DDE servers
883 * PARAMS
884 * idInst [I] Instance identifier
885 * hszService [I] Handle to service name string
886 * hszTopic [I] Handle to topic name string
887 * hConvList [I] Handle to conversation list
888 * pCC [I] Pointer to structure with context data
890 * RETURNS
891 * Success: Handle to new conversation list
892 * Failure: 0
894 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
895 HCONVLIST hConvList, LPCONVCONTEXT pCC )
897 FIXME("(%ld,%ld,%ld,%ld,%p): stub\n", idInst, hszService, hszTopic,
898 hConvList,pCC);
899 return 1;
903 /*****************************************************************
904 * DdeQueryNextServer16 [DDEML.5]
906 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
908 return DdeQueryNextServer(hConvList, hConvPrev);
912 /*****************************************************************
913 * DdeQueryNextServer [USER32.112]
915 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
917 FIXME("(%ld,%ld): stub\n",hConvList,hConvPrev);
918 return 0;
921 /*****************************************************************
922 * DdeQueryStringA [USER32.113]
924 *****************************************************************
926 * Change History
928 * Vn Date Author Comment
930 * 1.0 Dec 1998 Corel/Macadamian Initial version
931 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
934 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
936 DWORD err_no = 0;
937 DWORD ret = 0;
938 CHAR pString[MAX_BUFFER_LEN];
939 DDE_HANDLE_ENTRY *reference_inst;
941 FIXME(
942 "(%ld, 0x%lx, %p, %ld, %d): partial stub\n",
943 idInst,
944 hsz,
945 psz,
946 cchMax,
947 iCodePage);
948 if ( DDE_Max_Assigned_Instance == 0 )
950 /* Nothing has been initialised - exit now ! */
951 /* needs something for DdeGetLAstError even if the manual doesn't say so */
952 return FALSE;
954 WaitForSingleObject(handle_mutex,1000);
955 if ( (err_no=GetLastError()) != 0 )
957 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
959 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
960 /* needs something for DdeGetLAstError even if the manual doesn't say so */
961 return FALSE;
963 TRACE("Handle Mutex created/reserved\n");
965 /* First check instance
967 reference_inst = Find_Instance_Entry(idInst);
968 if ( reference_inst == NULL )
970 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
972 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
974 return FALSE;
977 if( iCodePage == CP_WINANSI )
979 /* If psz is null, we have to return only the length
980 * of the string.
982 if( psz == NULL )
984 psz = pString;
985 cchMax = MAX_BUFFER_LEN;
988 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
989 } else {
990 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
992 TRACE("returning pointer\n");
993 return ret;
996 /*****************************************************************
997 * DdeQueryStringW [USER32.114]
999 *****************************************************************
1001 * Change History
1003 * Vn Date Author Comment
1005 * 1.0 Dec 1998 Corel/Macadamian Initial version
1009 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1011 DWORD ret = 0;
1012 WCHAR pString[MAX_BUFFER_LEN];
1013 int factor = 1;
1015 FIXME(
1016 "(%ld, 0x%lx, %p, %ld, %d): stub\n",
1017 idInst,
1018 hsz,
1019 psz,
1020 cchMax,
1021 iCodePage);
1023 if( iCodePage == CP_WINUNICODE )
1025 /* If psz is null, we have to return only the length
1026 * of the string.
1028 if( psz == NULL )
1030 psz = pString;
1031 cchMax = MAX_BUFFER_LEN;
1032 /* Note: According to documentation if the psz parameter
1033 * was NULL this API must return the length of the string in bytes.
1035 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1037 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1039 return ret;
1042 /*****************************************************************
1044 * DdeQueryString16 (DDEML.23)
1046 ******************************************************************
1048 * Change History
1050 * Vn Date Author Comment
1052 * 1.0 March 1999 K Matthews stub only
1055 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, int codepage)
1057 FIXME("(%ld, 0x%lx, %p, %ld, %d): stub \n",
1058 idInst,
1059 hsz,
1060 lpsz,
1061 cchMax,
1062 codepage);
1063 return 0;
1067 /*****************************************************************
1068 * DdeDisconnectList (DDEML.6)
1070 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1072 return (BOOL16)DdeDisconnectList(hConvList);
1076 /******************************************************************************
1077 * DdeDisconnectList [USER32.98] Destroys list and terminates conversations
1079 * RETURNS
1080 * Success: TRUE
1081 * Failure: FALSE
1083 BOOL WINAPI DdeDisconnectList(
1084 HCONVLIST hConvList) /* [in] Handle to conversation list */
1086 FIXME("(%ld): stub\n", hConvList);
1087 return TRUE;
1091 /*****************************************************************
1092 * DdeConnect16 (DDEML.7)
1094 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1095 LPCONVCONTEXT16 pCC )
1097 FIXME("empty stub\n" );
1098 return 0;
1102 /*****************************************************************
1103 * DdeConnect (USER32.92)
1105 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1106 LPCONVCONTEXT pCC )
1108 FIXME("(0x%lx,%ld,%ld,%p): stub\n",idInst,hszService,hszTopic,
1109 pCC);
1110 return 0;
1114 /*****************************************************************
1115 * DdeDisconnect16 (DDEML.8)
1117 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1119 return (BOOL16)DdeDisconnect( hConv );
1122 /*****************************************************************
1123 * DdeSetUserHandle16 (DDEML.10)
1125 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1127 FIXME("(%ld,%ld,%ld): stub\n",hConv,id, hUser );
1128 return 0;
1131 /*****************************************************************
1132 * DdeCreateDataHandle16 (DDEML.14)
1134 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
1135 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
1136 UINT16 afCmd )
1138 return DdeCreateDataHandle(idInst,
1139 pSrc,
1141 cbOff,
1142 hszItem,
1143 wFmt,
1144 afCmd);
1147 /*****************************************************************
1148 * DdeCreateDataHandle (USER32.94)
1150 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
1151 DWORD cbOff, HSZ hszItem, UINT wFmt,
1152 UINT afCmd )
1154 FIXME(
1155 "(%ld,%p,%ld,%ld,0x%lx,%d,%d): stub\n",
1156 idInst,
1157 pSrc,
1159 cbOff,
1160 hszItem,
1161 wFmt,
1162 afCmd );
1164 return 0;
1167 /*****************************************************************
1168 * DdeDisconnect (USER32.97)
1170 BOOL WINAPI DdeDisconnect( HCONV hConv )
1172 FIXME("empty stub\n" );
1173 return 0;
1177 /*****************************************************************
1178 * DdeReconnect (DDEML.37) (USER32.115)
1180 HCONV WINAPI DdeReconnect( HCONV hConv )
1182 FIXME("empty stub\n" );
1183 return 0;
1187 /*****************************************************************
1188 * DdeCreateStringHandle16 (DDEML.21)
1190 *****************************************************************
1192 * Change History
1194 * Vn Date Author Comment
1196 * 1.0 ? ? basic stub
1197 * 1.1 June 1999 Keith Matthews amended onward call to supply default
1198 * code page if none supplied by caller
1200 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1202 if ( codepage )
1204 return DdeCreateStringHandleA( idInst, str, codepage );
1205 } else {
1206 TRACE("Default codepage supplied\n");
1207 return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1212 /*****************************************************************
1213 * DdeCreateStringHandleA [USER32.95]
1215 * RETURNS
1216 * Success: String handle
1217 * Failure: 0
1219 *****************************************************************
1221 * Change History
1223 * Vn Date Author Comment
1225 * 1.0 Dec 1998 Corel/Macadamian Initial version
1226 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1229 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1231 DWORD err_no = 0;
1232 HSZ hsz = 0;
1233 DDE_HANDLE_ENTRY *reference_inst;
1234 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1237 if ( DDE_Max_Assigned_Instance == 0 )
1239 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1240 return FALSE;
1242 WaitForSingleObject(handle_mutex,1000);
1243 if ( (err_no=GetLastError()) != 0 )
1245 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1247 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
1248 return DMLERR_SYS_ERROR;
1250 TRACE("Handle Mutex created/reserved\n");
1252 /* First check instance
1254 reference_inst = Find_Instance_Entry(idInst);
1255 if ( reference_inst == NULL )
1257 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1259 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1261 return 0;
1264 if (codepage==CP_WINANSI)
1266 hsz = GlobalAddAtomA (psz);
1267 /* Save the handle so we know to clean it when
1268 * uninitialize is called.
1270 TRACE("added atom %s with HSZ 0x%lx, \n",debugstr_a(psz),hsz);
1271 InsertHSZNode( hsz, reference_inst );
1272 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1274 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1275 return 0;
1277 TRACE("Returning pointer\n");
1278 return hsz;
1279 } else {
1280 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1282 TRACE("Returning error\n");
1283 return 0;
1287 /******************************************************************************
1288 * DdeCreateStringHandleW [USER32.96] Creates handle to identify string
1290 * RETURNS
1291 * Success: String handle
1292 * Failure: 0
1294 *****************************************************************
1296 * Change History
1298 * Vn Date Author Comment
1300 * 1.0 Dec 1998 Corel/Macadamian Initial version
1301 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1304 HSZ WINAPI DdeCreateStringHandleW(
1305 DWORD idInst, /* [in] Instance identifier */
1306 LPCWSTR psz, /* [in] Pointer to string */
1307 INT codepage) /* [in] Code page identifier */
1309 DWORD err_no = 0;
1310 DDE_HANDLE_ENTRY *reference_inst;
1311 HSZ hsz = 0;
1313 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1316 if ( DDE_Max_Assigned_Instance == 0 )
1318 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1319 return FALSE;
1321 WaitForSingleObject(handle_mutex,1000);
1322 if ( (err_no=GetLastError()) != 0 )
1324 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1326 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
1327 return DMLERR_SYS_ERROR;
1329 TRACE("CreateString - Handle Mutex created/reserved\n");
1331 /* First check instance
1333 reference_inst = Find_Instance_Entry(idInst);
1334 if ( reference_inst == NULL )
1336 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1338 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1340 return 0;
1343 FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1345 if (codepage==CP_WINUNICODE)
1347 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1350 hsz = GlobalAddAtomW (psz);
1351 /* Save the handle so we know to clean it when
1352 * uninitialize is called.
1354 InsertHSZNode( hsz, reference_inst );
1355 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1357 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1358 return 0;
1360 TRACE("Returning pointer\n");
1361 return hsz;
1362 } else {
1363 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1365 TRACE("Returning error\n");
1366 return 0;
1370 /*****************************************************************
1371 * DdeFreeStringHandle16 (DDEML.22)
1373 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1375 FIXME("idInst %ld hsz 0x%lx\n",idInst,hsz);
1376 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1380 /*****************************************************************
1381 * DdeFreeStringHandle (USER32.101)
1382 * RETURNS: success: nonzero
1383 * fail: zero
1385 *****************************************************************
1387 * Change History
1389 * Vn Date Author Comment
1391 * 1.0 Dec 1998 Corel/Macadamian Initial version
1392 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1395 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1397 DWORD err_no = 0;
1398 DWORD prev_err = 0;
1399 DDE_HANDLE_ENTRY *reference_inst;
1400 TRACE("(%ld,%ld): \n",idInst,hsz);
1401 if ( DDE_Max_Assigned_Instance == 0 )
1403 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1404 return TRUE;
1406 if ( ( prev_err = GetLastError()) != 0 )
1408 /* something earlier failed !! */
1409 ERR("Error %li before WaitForSingleObject - trying to continue\n",prev_err);
1411 WaitForSingleObject(handle_mutex,1000);
1412 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
1414 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1416 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
1417 return DMLERR_SYS_ERROR;
1419 TRACE("Handle Mutex created/reserved\n");
1421 /* First check instance
1423 reference_inst = Find_Instance_Entry(idInst);
1424 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1426 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
1427 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1428 return TRUE;
1432 /* Remove the node associated with this HSZ.
1434 RemoveHSZNode( hsz , reference_inst);
1435 /* Free the string associated with this HSZ.
1437 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1438 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1442 /*****************************************************************
1443 * DdeFreeDataHandle16 (DDEML.19)
1445 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1447 return (BOOL)DdeFreeDataHandle( hData );
1451 /*****************************************************************
1452 * DdeFreeDataHandle (USER32.100)
1454 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1456 FIXME("empty stub\n" );
1457 return TRUE;
1463 /*****************************************************************
1464 * DdeKeepStringHandle16 (DDEML.24)
1466 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1468 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1472 /*****************************************************************
1473 * DdeKeepStringHandle (USER32.108)
1475 * RETURNS: success: nonzero
1476 * fail: zero
1478 *****************************************************************
1480 * Change History
1482 * Vn Date Author Comment
1484 * 1.0 ? ? Stub only
1485 * 1.1 Jun 1999 Keith Matthews First cut implementation
1488 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1491 DWORD prev_err = 0;
1492 DWORD err_no = 0;
1493 DDE_HANDLE_ENTRY *reference_inst;
1494 TRACE("(%ld,%ld): \n",idInst,hsz);
1495 if ( DDE_Max_Assigned_Instance == 0 )
1497 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1498 return FALSE;
1500 if ( ( prev_err = GetLastError()) != 0 )
1502 /* something earlier failed !! */
1503 ERR("Error %li before WaitForSingleObject - trying to continue\n",prev_err);
1505 WaitForSingleObject(handle_mutex,1000);
1506 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
1508 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1510 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
1511 return FALSE;
1513 TRACE("Handle Mutex created/reserved\n");
1515 /* First check instance
1517 reference_inst = Find_Instance_Entry(idInst);
1518 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1520 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
1521 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1522 return FALSE;
1523 return FALSE;
1525 DdeReserveAtom(reference_inst,hsz);
1526 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1527 return TRUE;
1531 /*****************************************************************
1532 * DdeClientTransaction16 (DDEML.11)
1534 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1535 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1536 UINT16 wType, DWORD dwTimeout,
1537 LPDWORD pdwResult )
1539 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1540 wFmt, wType, dwTimeout, pdwResult );
1544 /*****************************************************************
1545 * DdeClientTransaction (USER32.90)
1547 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1548 HCONV hConv, HSZ hszItem, UINT wFmt,
1549 UINT wType, DWORD dwTimeout,
1550 LPDWORD pdwResult )
1552 FIXME("empty stub\n" );
1553 return 0;
1556 /*****************************************************************
1558 * DdeAbandonTransaction16 (DDEML.12)
1561 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1562 DWORD idTransaction )
1564 FIXME("empty stub\n" );
1565 return TRUE;
1569 /*****************************************************************
1571 * DdeAbandonTransaction (USER32.87)
1573 ******************************************************************
1575 * Change History
1577 * Vn Date Author Comment
1579 * 1.0 March 1999 K Matthews stub only
1581 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1582 DWORD idTransaction )
1584 FIXME("empty stub\n" );
1585 return TRUE;
1588 /*****************************************************************
1589 * DdePostAdvise16 [DDEML.13]
1591 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1593 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1597 /******************************************************************************
1598 * DdePostAdvise [USER32.110] Send transaction to DDE callback function.
1600 * RETURNS
1601 * Success: TRUE
1602 * Failure: FALSE
1604 BOOL WINAPI DdePostAdvise(
1605 DWORD idInst, /* [in] Instance identifier */
1606 HSZ hszTopic, /* [in] Handle to topic name string */
1607 HSZ hszItem) /* [in] Handle to item name string */
1609 FIXME("(%ld,%ld,%ld): stub\n",idInst,hszTopic,hszItem);
1610 return TRUE;
1614 /*****************************************************************
1615 * DdeAddData16 (DDEML.15)
1617 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1618 DWORD cbOff )
1620 FIXME("empty stub\n" );
1621 return 0;
1624 /*****************************************************************
1626 * DdeAddData (USER32.89)
1628 ******************************************************************
1630 * Change History
1632 * Vn Date Author Comment
1634 * 1.0 March 1999 K Matthews stub only
1636 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1637 DWORD cbOff )
1639 FIXME("empty stub\n" );
1640 return 0;
1644 /*****************************************************************
1646 * DdeImpersonateClient (USER32.105)
1648 ******************************************************************
1650 * Change History
1652 * Vn Date Author Comment
1654 * 1.0 March 1999 K Matthews stub only
1657 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1659 FIXME("empty stub\n" );
1660 return TRUE;
1664 /*****************************************************************
1666 * DdeSetQualityOfService (USER32.116)
1668 ******************************************************************
1670 * Change History
1672 * Vn Date Author Comment
1674 * 1.0 March 1999 K Matthews stub only
1677 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1678 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1680 FIXME("empty stub\n" );
1681 return TRUE;
1684 /*****************************************************************
1686 * DdeSetUserHandle (USER32.117)
1688 ******************************************************************
1690 * Change History
1692 * Vn Date Author Comment
1694 * 1.0 March 1999 K Matthews stub only
1697 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1699 FIXME("empty stub\n" );
1700 return TRUE;
1703 /******************************************************************************
1704 * DdeGetData [USER32.102] Copies data from DDE object ot local buffer
1706 * RETURNS
1707 * Size of memory object associated with handle
1709 DWORD WINAPI DdeGetData(
1710 HDDEDATA hData, /* [in] Handle to DDE object */
1711 LPBYTE pDst, /* [in] Pointer to destination buffer */
1712 DWORD cbMax, /* [in] Amount of data to copy */
1713 DWORD cbOff) /* [in] Offset to beginning of data */
1715 FIXME("(%ld,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1716 return cbMax;
1720 /*****************************************************************
1721 * DdeGetData16 [DDEML.16]
1723 DWORD WINAPI DdeGetData16(
1724 HDDEDATA hData,
1725 LPBYTE pDst,
1726 DWORD cbMax,
1727 DWORD cbOff)
1729 return DdeGetData(hData, pDst, cbMax, cbOff);
1733 /*****************************************************************
1734 * DdeAccessData16 (DDEML.17)
1736 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1738 return DdeAccessData(hData, pcbDataSize);
1741 /*****************************************************************
1742 * DdeAccessData (USER32.88)
1744 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1746 FIXME("(%ld,%p): stub\n", hData, pcbDataSize);
1747 return 0;
1750 /*****************************************************************
1751 * DdeUnaccessData16 (DDEML.18)
1753 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1755 return DdeUnaccessData(hData);
1758 /*****************************************************************
1759 * DdeUnaccessData (USER32.118)
1761 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1763 FIXME("(0x%lx): stub\n", hData);
1765 return 0;
1768 /*****************************************************************
1769 * DdeEnableCallback16 (DDEML.26)
1771 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1773 return DdeEnableCallback(idInst, hConv, wCmd);
1776 /*****************************************************************
1777 * DdeEnableCallback (USER32.99)
1779 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1781 FIXME("(%ld, 0x%lx, %d) stub\n", idInst, hConv, wCmd);
1783 return 0;
1786 /*****************************************************************
1787 * DdeNameService16 (DDEML.27)
1789 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1790 UINT16 afCmd )
1792 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1796 /******************************************************************************
1797 * DdeNameService [USER32.109] {Un}registers service name of DDE server
1799 * PARAMS
1800 * idInst [I] Instance identifier
1801 * hsz1 [I] Handle to service name string
1802 * hsz2 [I] Reserved
1803 * afCmd [I] Service name flags
1805 * RETURNS
1806 * Success: Non-zero
1807 * Failure: 0
1809 *****************************************************************
1811 * Change History
1813 * Vn Date Author Comment
1815 * 1.0 ? ? Stub
1816 * 1.1 Apr 1999 Keith Matthews Added trap for non-existent instance (uninitialised instance 0
1817 * used by some MS programs for unfathomable reasons)
1818 * 1.2 May 1999 Keith Matthews Added parameter validation and basic service name handling.
1819 * Still needs callback parts
1822 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1823 UINT afCmd )
1825 UINT Cmd_flags = afCmd;
1826 ServiceNode* this_service, *reference_service ;
1827 CHAR SNameBuffer[MAX_BUFFER_LEN];
1828 UINT rcode;
1829 DWORD err_no = 0;
1830 DDE_HANDLE_ENTRY *this_instance;
1831 DDE_HANDLE_ENTRY *reference_inst;
1832 this_service = NULL;
1833 FIXME("(%ld,%ld,%ld,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1834 if ( DDE_Max_Assigned_Instance == 0 )
1836 /* Nothing has been initialised - exit now !
1837 * needs something for DdeGetLastError */
1838 return 0L;
1840 WaitForSingleObject(handle_mutex,1000);
1841 if ( (err_no=GetLastError()) != 0 )
1843 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1845 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
1846 return DMLERR_SYS_ERROR;
1848 TRACE("Handle Mutex created/reserved\n");
1850 /* First check instance
1852 reference_inst = Find_Instance_Entry(idInst);
1853 this_instance = reference_inst;
1854 if (reference_inst == NULL)
1856 TRACE("Instance not found as initialised\n");
1857 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return TRUE;
1858 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1859 return FALSE;
1863 if ( hsz2 != 0L )
1865 /* Illegal, reserved parameter
1867 reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1868 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1869 FIXME("Reserved parameter no-zero !!\n");
1870 return FALSE;
1872 if ( hsz1 == 0L )
1875 * General unregister situation
1877 if ( afCmd != DNS_UNREGISTER )
1879 /* don't know if we should check this but it makes sense
1880 * why supply REGISTER or filter flags if de-registering all
1882 TRACE("General unregister unexpected flags\n");
1883 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1884 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1885 return FALSE;
1887 /* Loop to find all registered service and de-register them
1889 if ( reference_inst->ServiceNames == NULL )
1891 /* None to unregister !!
1893 TRACE("General de-register - nothing registered\n");
1894 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1895 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1896 return FALSE;
1897 } else
1899 this_service = reference_inst->ServiceNames;
1900 while ( this_service->next != NULL)
1902 TRACE("general deregister - iteration\n");
1903 reference_service = this_service;
1904 this_service = this_service->next;
1905 DdeReleaseAtom(reference_inst,reference_service->hsz);
1906 HeapFree(SystemHeap, 0, reference_service); /* finished - release heap space used as work store */
1908 DdeReleaseAtom(reference_inst,this_service->hsz);
1909 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space used as work store */
1910 reference_inst->ServiceNames = NULL;
1911 TRACE("General de-register - finished\n");
1913 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1914 return TRUE;
1916 TRACE("Specific name action detected\n");
1917 reference_service = Find_Service_Name(hsz1,reference_inst);
1918 if (( Cmd_flags && DNS_REGISTER ) == DNS_REGISTER )
1920 /* Register new service name
1923 rcode=GlobalGetAtomNameA(hsz1,SNameBuffer,MAX_ATOM_LEN);
1924 Cmd_flags = Cmd_flags ^ DNS_REGISTER;
1925 this_service= (ServiceNode*)HeapAlloc( SystemHeap, 0, sizeof(ServiceNode) );
1926 this_service->next = NULL;
1927 this_service->hsz = hsz1;
1928 this_service->FilterOn = TRUE;
1929 if ( reference_inst->ServiceNames == NULL )
1931 /* easy one - nothing else there
1933 TRACE("Adding 1st service name\n");
1934 reference_inst->ServiceNames = this_service;
1935 GlobalAddAtomA(SNameBuffer);
1936 } else
1938 /* more difficult - may have also been registered
1940 if (reference_service != NULL )
1942 /* Service name already registered !!
1943 * what do we do ?
1945 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space used as work store */
1946 FIXME("Trying to register already registered service !!\n");
1947 } else
1949 /* Add this one into the chain
1951 TRACE("Adding subsequent service name\n");
1952 this_service->next = reference_inst->ServiceNames;
1953 reference_inst->ServiceNames = this_service;
1954 GlobalAddAtomA(SNameBuffer);
1958 if ( (Cmd_flags && DNS_UNREGISTER ) == DNS_UNREGISTER )
1960 /* De-register service name
1962 Cmd_flags = Cmd_flags ^ DNS_UNREGISTER;
1963 if ( reference_inst->ServiceNames == NULL )
1965 /* easy one - already done
1967 } else
1969 /* more difficult - must hook out of sequence
1971 this_instance = reference_inst;
1972 if (this_service == NULL )
1974 /* Service name not registered !!
1975 * what do we do ?
1977 FIXME("Trying to de-register unregistered service !!\n");
1978 } else
1980 /* Delete this one from the chain
1982 if ( reference_inst->ServiceNames == this_service )
1984 /* special case - the first/only entry
1986 reference_inst->ServiceNames = this_service->next;
1987 } else
1989 /* general case
1991 reference_service->next= reference_inst->ServiceNames;
1992 while ( reference_service->next!= this_service )
1994 reference_service = reference_service->next;
1996 reference_service->next= this_service->next;
1998 DdeReleaseAtom(reference_inst,this_service->hsz);
1999 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space */
2003 if ( ( Cmd_flags && DNS_FILTEROFF ) != DNS_FILTEROFF )
2005 /* Set filter flags on to hold notifications of connection
2007 * test coded this way as this is the default setting
2009 Cmd_flags = Cmd_flags ^ DNS_FILTERON;
2010 if ( ( reference_inst->ServiceNames == NULL ) || ( this_service == NULL) )
2012 /* trying to filter where no service names !!
2014 reference_inst->Last_Error = DMLERR_DLL_USAGE;
2015 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
2016 return FALSE;
2017 } else
2019 this_service->FilterOn = TRUE;
2022 if ( ( Cmd_flags && DNS_FILTEROFF ) == DNS_FILTEROFF )
2024 /* Set filter flags on to hold notifications of connection
2026 Cmd_flags = Cmd_flags ^ DNS_FILTEROFF;
2027 if ( ( reference_inst->ServiceNames == NULL ) || ( this_service == NULL) )
2029 /* trying to filter where no service names !!
2031 reference_inst->Last_Error = DMLERR_DLL_USAGE;
2032 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
2033 return FALSE;
2034 } else
2036 this_service->FilterOn = FALSE;
2039 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
2040 return TRUE;
2044 /*****************************************************************
2045 * DdeGetLastError16 (DDEML.20)
2047 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
2049 return (UINT16)DdeGetLastError( idInst );
2053 /******************************************************************************
2054 * DdeGetLastError [USER32.103] Gets most recent error code
2056 * PARAMS
2057 * idInst [I] Instance identifier
2059 * RETURNS
2060 * Last error code
2062 *****************************************************************
2064 * Change History
2066 * Vn Date Author Comment
2068 * 1.0 ? ? Stub
2069 * 1.1 Apr 1999 Keith Matthews Added response for non-existent instance (uninitialised instance 0
2070 * used by some MS programs for unfathomable reasons)
2071 * 1.2 May 1999 Keith Matthews Added interrogation of Last_Error for instance handle where found.
2074 UINT WINAPI DdeGetLastError( DWORD idInst )
2076 DWORD error_code;
2077 DWORD err_no = 0;
2078 DWORD prev_err = 0;
2079 DDE_HANDLE_ENTRY *reference_inst;
2080 FIXME("(%ld): stub\n",idInst);
2081 if ( DDE_Max_Assigned_Instance == 0 )
2083 /* Nothing has been initialised - exit now ! */
2084 return DMLERR_DLL_NOT_INITIALIZED;
2086 if ( ( prev_err = GetLastError()) != 0 )
2088 /* something earlier failed !! */
2089 ERR("Error %li before WaitForSingleObject - trying to continue\n",prev_err);
2091 WaitForSingleObject(handle_mutex,1000);
2092 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
2094 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
2096 ERR("WaitForSingleObject failed - handle list %li\n",err_no);
2097 return DMLERR_SYS_ERROR;
2099 TRACE("Handle Mutex created/reserved\n");
2101 /* First check instance
2103 reference_inst = Find_Instance_Entry(idInst);
2104 if (reference_inst == NULL)
2106 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
2107 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2108 return DMLERR_DLL_NOT_INITIALIZED;
2111 error_code = reference_inst->Last_Error;
2112 reference_inst->Last_Error = 0;
2113 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
2114 return error_code;
2118 /*****************************************************************
2119 * DdeCmpStringHandles16 (DDEML.36)
2121 int WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2123 return DdeCmpStringHandles(hsz1, hsz2);
2126 /*****************************************************************
2127 * DdeCmpStringHandles (USER32.91)
2129 * Compares the value of two string handles. This comparison is
2130 * not case sensitive.
2132 * Returns:
2133 * -1 The value of hsz1 is zero or less than hsz2
2134 * 0 The values of hsz 1 and 2 are the same or both zero.
2135 * 1 The value of hsz2 is zero of less than hsz1
2137 int WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2139 CHAR psz1[MAX_BUFFER_LEN];
2140 CHAR psz2[MAX_BUFFER_LEN];
2141 int ret = 0;
2142 int ret1, ret2;
2144 TRACE("handle 1, handle 2\n" );
2146 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2147 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2148 /* Make sure we found both strings.
2150 if( ret1 == 0 && ret2 == 0 )
2152 /* If both are not found, return both "zero strings".
2154 ret = 0;
2156 else if( ret1 == 0 )
2158 /* If hsz1 is a not found, return hsz1 is "zero string".
2160 ret = -1;
2162 else if( ret2 == 0 )
2164 /* If hsz2 is a not found, return hsz2 is "zero string".
2166 ret = 1;
2168 else
2170 /* Compare the two strings we got ( case insensitive ).
2172 ret = strcasecmp( psz1, psz2 );
2173 /* Since strcmp returns any number smaller than
2174 * 0 when the first string is found to be less than
2175 * the second one we must make sure we are returning
2176 * the proper values.
2178 if( ret < 0 )
2180 ret = -1;
2182 else if( ret > 0 )
2184 ret = 1;
2188 return ret;
2191 /*****************************************************************
2192 * PackDDElParam (USER32.414)
2194 * RETURNS
2195 * success: nonzero
2196 * failure: zero
2198 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2200 FIXME("stub.\n");
2201 return 0;
2205 /*****************************************************************
2206 * UnpackDDElParam (USER32.562)
2208 * RETURNS
2209 * success: nonzero
2210 * failure: zero
2212 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
2213 UINT *uiLo, UINT *uiHi)
2215 FIXME("stub.\n");
2216 return 0;
2220 /*****************************************************************
2221 * FreeDDElParam (USER32.204)
2223 * RETURNS
2224 * success: nonzero
2225 * failure: zero
2227 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
2229 FIXME("stub.\n");
2230 return 0;
2233 /*****************************************************************
2234 * ReuseDDElParam (USER32.446)
2237 UINT WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2238 UINT uiLi, UINT uiHi)
2240 FIXME("stub.\n");
2241 return 0;
2244 /******************************************************************
2245 * DdeQueryConvInfo16 (DDEML.9)
2248 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2250 FIXME("stub.\n");
2251 return 0;
2255 /******************************************************************
2256 * DdeQueryConvInfo (USER32.111)
2259 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)
2261 FIXME("stub.\n");
2262 return 0;