4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Len White
6 * Copyright 1999 Keith Matthews
9 /* Only empty stubs for now */
18 #include "debugtools.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)
34 LPVOID lpSecurityDescriptor;
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;
54 typedef struct tagServiceNode ServiceNode;
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;
72 UINT Txn_count; /* count transactions open to simplify closure */
74 ServiceNode* ServiceNames;
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 *DDEInstanceAccess = "DDEMaxInstance";
80 static const char *DDEHandleAccess = "DDEHandleAccess";
81 static HANDLE inst_count_mutex = 0;
82 static HANDLE handle_mutex = 0;
88 /******************************************************************************
89 * RemoveHSZNodes (INTERNAL)
91 * Remove a node from the list of HSZ nodes.
93 ******************************************************************************
97 * Vn Date Author Comment
99 * 1.0 Dec 1998 Corel/Macadamian Initial version
100 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
103 static void RemoveHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
105 HSZNode* pPrev = NULL;
106 HSZNode* pCurrent = NULL;
108 /* Set the current node at the start of the list.
110 pCurrent = reference_inst->Node_list;
111 /* While we have more nodes.
113 while( pCurrent != NULL )
115 /* If we found the node we were looking for.
117 if( pCurrent->hsz == hsz )
121 /* If the first node in the list is to to be removed.
122 * Set the global list pointer to the next node.
124 if( pCurrent == reference_inst->Node_list )
126 reference_inst->Node_list = pCurrent->next;
128 /* Just fix the pointers has to skip the current
129 * node so we can delete it.
133 pPrev->next = pCurrent->next;
135 /* Destroy this node.
140 /* Save the previous node pointer.
143 /* Move on to the next node.
145 pCurrent = pCurrent->next;
149 /******************************************************************************
150 * FreeAndRemoveHSZNodes (INTERNAL)
152 * Frees up all the strings still allocated in the list and
153 * remove all the nodes from the list of HSZ nodes.
155 ******************************************************************************
159 * Vn Date Author Comment
161 * 1.0 Dec 1998 Corel/Macadamian Initial version
162 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
165 static void FreeAndRemoveHSZNodes( DWORD idInst, DDE_HANDLE_ENTRY * reference_inst )
167 /* Free any strings created in this instance.
169 while( reference_inst->Node_list != NULL )
171 DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
175 /******************************************************************************
176 * InsertHSZNode (INTERNAL)
178 * Insert a node to the head of the list.
180 ******************************************************************************
184 * Vn Date Author Comment
186 * 1.0 Dec 1998 Corel/Macadamian Initial version
187 * 1.1 Mar 1999 Keith Matthews Added instance handling
188 * 1.2 Jun 1999 Keith Matthews Added Usage count handling
191 static void InsertHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
195 HSZNode* pNew = NULL;
196 /* Create a new node for this HSZ.
198 pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
201 /* Set the handle value.
204 /* Attach the node to the head of the list. i.e most recently added is first
206 pNew->next = reference_inst->Node_list;
208 /* The new node is now at the head of the list
209 * so set the global list pointer to it.
211 reference_inst->Node_list = pNew;
212 TRACE("HSZ node list entry added\n");
217 /*****************************************************************************
218 * Find_Instance_Entry
220 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
221 * for an instance Id, or NULL if the entry does not exist
223 * ASSUMES the mutex protecting the handle entry list is reserved before calling
225 ******************************************************************************
229 * Vn Date Author Comment
231 * 1.0 March 1999 Keith Matthews 1st implementation
233 DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
235 DDE_HANDLE_ENTRY * reference_inst;
236 reference_inst = DDE_Handle_Table_Base;
237 while ( reference_inst != NULL )
239 if ( reference_inst->Instance_id == InstId )
241 TRACE("Instance entry found\n");
242 return reference_inst;
244 reference_inst = reference_inst->Next_Entry;
246 TRACE("Instance entry missing\n");
250 /*****************************************************************************
253 * generic routine to return a pointer to the relevant ServiceNode
254 * for a given service name, or NULL if the entry does not exist
256 * ASSUMES the mutex protecting the handle entry list is reserved before calling
258 ******************************************************************************
262 * Vn Date Author Comment
264 * 1.0 May 1999 Keith Matthews 1st implementation
266 ServiceNode *Find_Service_Name (HSZ Service_Name, DDE_HANDLE_ENTRY* this_instance)
268 ServiceNode * reference_name= this_instance->ServiceNames;
269 while ( reference_name != NULL )
271 if ( reference_name->hsz == Service_Name )
273 TRACE("Service Name found\n");
274 return reference_name;
276 reference_name = reference_name->next;
278 TRACE("Service name missing\n");
283 /******************************************************************************
284 * Release_reserved_mutex
286 * generic routine to release a reserved mutex
289 ******************************************************************************
293 * Vn Date Author Comment
295 * 1.0 Jan 1999 Keith Matthews Initial version
296 * 1.1 Mar 1999 Keith Matthews Corrected Heap handling. Corrected re-initialisation handling
297 * 1.2 Aug 1999 Jürgen Schmied Corrected error handling
300 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i ,
301 DDE_HANDLE_ENTRY *this_instance)
303 if (!ReleaseMutex(mutex))
305 ERR("ReleaseMutex failed - %s mutex %li\n",mutex_name,GetLastError());
306 HeapFree(SystemHeap, 0, this_instance);
307 if ( release_handle_m )
309 ReleaseMutex(handle_mutex);
311 return DMLERR_SYS_ERROR;
313 if ( release_this_i )
315 HeapFree(SystemHeap, 0, this_instance);
317 return DMLERR_NO_ERROR;
320 /******************************************************************************
323 * generic routine to wait for the mutex
326 ******************************************************************************
330 * Vn Date Author Comment
332 * 1.0 Aug 1999 Juergen Schmied Initial version
335 static BOOL WaitForMutex (HANDLE mutex)
339 result = WaitForSingleObject(mutex,1000);
341 /* both errors should never occur */
342 if (WAIT_TIMEOUT == result)
344 ERR("WaitForSingleObject timed out\n");
348 if (WAIT_FAILED == result)
350 ERR("WaitForSingleObject failed - error %li\n", GetLastError());
355 /******************************************************************************
356 * IncrementInstanceId
358 * generic routine to increment the max instance Id and allocate a new application instance
360 ******************************************************************************
364 * Vn Date Author Comment
366 * 1.0 Jan 1999 Keith Matthews Initial version
369 DWORD IncrementInstanceId( DDE_HANDLE_ENTRY *this_instance)
371 SECURITY_ATTRIBUTES s_attrib;
373 /* Need to set up Mutex in case it is not already present */
374 /* increment handle count & get value */
375 if ( !inst_count_mutex )
377 s_attrib.bInheritHandle = TRUE;
378 s_attrib.lpSecurityDescriptor = NULL;
379 s_attrib.nLength = sizeof(s_attrib);
380 inst_count_mutex = CreateMutexA(&s_attrib,1,DDEInstanceAccess); /* 1st time through */
381 inst_count_mutex = ConvertToGlobalHandle(inst_count_mutex); /* fixme when having seperate adresspaces*/
383 if ( !WaitForMutex(inst_count_mutex) )
385 return DMLERR_SYS_ERROR;
388 if ( !inst_count_mutex )
390 ERR("CreateMutex failed - inst_count %li\n",GetLastError());
391 Release_reserved_mutex (handle_mutex,"handle_mutex",0,1,this_instance);
392 return DMLERR_SYS_ERROR;
394 DDE_Max_Assigned_Instance++;
395 this_instance->Instance_id = DDE_Max_Assigned_Instance;
396 TRACE("New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
397 if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0,this_instance)) return DMLERR_SYS_ERROR;
398 return DMLERR_NO_ERROR;
401 /******************************************************************************
402 * FindNotifyMonitorCallbacks
404 * Routine to find instances that need to be notified via their callback
405 * of some event they are monitoring
407 ******************************************************************************
411 * Vn Date Author Comment
413 * 1.0 May 1999 Keith Matthews Initial Version
417 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
419 DDE_HANDLE_ENTRY *InstanceHandle;
420 InstanceHandle = DDE_Handle_Table_Base;
421 while ( InstanceHandle != NULL )
423 if ( (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
425 /* Found an instance registered as monitor and is not ourselves
426 * use callback to notify where appropriate
429 InstanceHandle = InstanceHandle->Next_Entry;
433 /******************************************************************************
436 * Routine to make an extra Add on an atom to reserve it a bit longer
438 ******************************************************************************
442 * Vn Date Author Comment
444 * 1.0 Jun 1999 Keith Matthews Initial Version
448 void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
450 CHAR SNameBuffer[MAX_BUFFER_LEN];
452 if ( reference_inst->Unicode)
454 rcode=GlobalGetAtomNameW(hsz,(LPWSTR)&SNameBuffer,MAX_ATOM_LEN);
455 GlobalAddAtomW((LPWSTR)SNameBuffer);
457 rcode=GlobalGetAtomNameA(hsz,SNameBuffer,MAX_ATOM_LEN);
458 GlobalAddAtomA(SNameBuffer);
463 /******************************************************************************
466 * Routine to make a delete on an atom to release it a bit sooner
468 ******************************************************************************
472 * Vn Date Author Comment
474 * 1.0 Jun 1999 Keith Matthews Initial Version
478 void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
480 CHAR SNameBuffer[MAX_BUFFER_LEN];
482 if ( reference_inst->Unicode)
484 rcode=GlobalGetAtomNameW(hsz,(LPWSTR)&SNameBuffer,MAX_ATOM_LEN);
485 GlobalAddAtomW((LPWSTR)SNameBuffer);
487 rcode=GlobalGetAtomNameA(hsz,SNameBuffer,MAX_ATOM_LEN);
488 GlobalAddAtomA(SNameBuffer);
492 /******************************************************************************
493 * DdeInitialize16 (DDEML.2)
495 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
496 DWORD afCmd, DWORD ulRes)
498 TRACE("DdeInitialize16 called - calling DdeInitializeA\n");
499 return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
504 /******************************************************************************
505 * DdeInitializeA (USER32.106)
507 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
508 DWORD afCmd, DWORD ulRes )
510 TRACE("DdeInitializeA called - calling DdeInitializeW\n");
511 return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
515 /******************************************************************************
516 * DdeInitializeW [USER32.107]
517 * Registers an application with the DDEML
520 * pidInst [I] Pointer to instance identifier
521 * pfnCallback [I] Pointer to callback function
522 * afCmd [I] Set of command and filter flags
526 * Success: DMLERR_NO_ERROR
527 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
529 ******************************************************************************
533 * Vn Date Author Comment
535 * 1.0 Pre 1998 Alexandre/Len Initial Stub
536 * 1.1 Jan 1999 Keith Matthews Initial (near-)complete version
537 * 1.2 Mar 1999 Keith Matthews Corrected Heap handling, CreateMutex failure handling
540 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
541 DWORD afCmd, DWORD ulRes )
544 /* probably not really capable of handling mutliple processes, but should handle
545 * multiple instances within one process */
547 SECURITY_ATTRIBUTES *s_att= NULL;
548 SECURITY_ATTRIBUTES s_attrib;
550 DDE_HANDLE_ENTRY *this_instance;
551 DDE_HANDLE_ENTRY *reference_inst;
556 ERR("Reserved value not zero? What does this mean?\n");
557 FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
559 /* trap this and no more until we know more */
560 return DMLERR_NO_ERROR;
564 /* this one may be wrong - MS dll seems to accept the condition,
565 leave this until we find out more !! */
568 /* can't set up the instance with nothing to act as a callback */
569 TRACE("No callback provided\n");
570 return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
573 /* grab enough heap for one control struct - not really necessary for re-initialise
574 * but allows us to use same validation routines */
575 this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( SystemHeap, 0, sizeof(DDE_HANDLE_ENTRY) );
576 if ( this_instance == NULL )
578 /* catastrophe !! warn user & abort */
579 ERR("Instance create failed - out of memory\n");
580 return DMLERR_SYS_ERROR;
582 this_instance->Next_Entry = NULL;
583 this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
585 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
587 this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
588 this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
589 this_instance->CallBack=*pfnCallback;
590 this_instance->Txn_count=0;
591 this_instance->Unicode = TRUE;
592 this_instance->Win16 = FALSE;
593 this_instance->Node_list = NULL; /* node will be added later */
594 this_instance->Monitor_flags = afCmd & MF_MASK;
595 this_instance->ServiceNames = NULL;
597 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
599 this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
601 if ( ! this_instance->Client_only )
604 /* Check for other way of setting Client-only !! */
606 this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
607 ==CBF_FAIL_ALLSVRXACTIONS;
610 TRACE("instance created - checking validity \n");
612 if( *pidInst == 0 ) {
613 /* Initialisation of new Instance Identifier */
614 TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
615 if ( DDE_Max_Assigned_Instance == 0 )
617 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
618 /* Need to set up Mutex in case it is not already present */
619 s_att->bInheritHandle = TRUE;
620 s_att->lpSecurityDescriptor = NULL;
621 s_att->nLength = sizeof(s_att);
622 handle_mutex = CreateMutexA(s_att,1,DDEHandleAccess);
623 handle_mutex = ConvertToGlobalHandle(handle_mutex); /* fixme when having seperate adresspaces*/
624 if ( !handle_mutex ) {
625 ERR("CreateMutex failed - handle list %li\n",GetLastError());
626 HeapFree(SystemHeap, 0, this_instance);
627 return DMLERR_SYS_ERROR;
630 if ( !WaitForMutex(handle_mutex) )
632 return DMLERR_SYS_ERROR;
636 TRACE("Handle Mutex created/reserved\n");
637 if (DDE_Handle_Table_Base == NULL )
639 /* can't be another instance in this case, assign to the base pointer */
640 DDE_Handle_Table_Base= this_instance;
642 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
644 * ------------------------------- NOTE NOTE NOTE --------------------------
646 * the manual is not clear if this condition
647 * applies to the first call to DdeInitialize from an application, or the
648 * first call for a given callback !!!
651 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
652 TRACE("First application instance detected OK\n");
653 /* allocate new instance ID */
654 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
657 /* really need to chain the new one in to the latest here, but after checking conditions
658 * such as trying to start a conversation from an application trying to monitor */
659 reference_inst = DDE_Handle_Table_Base;
660 TRACE("Subsequent application instance - starting checks\n");
661 while ( reference_inst->Next_Entry != NULL )
664 * This set of tests will work if application uses same instance Id
665 * at application level once allocated - which is what manual implies
666 * should happen. If someone tries to be
667 * clever (lazy ?) it will fail to pick up that later calls are for
668 * the same application - should we trust them ?
670 if ( this_instance->Instance_id == reference_inst->Instance_id)
672 /* Check 1 - must be same Client-only state */
674 if ( this_instance->Client_only != reference_inst->Client_only)
676 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
677 return DMLERR_SYS_ERROR;
678 return DMLERR_DLL_USAGE;
681 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
683 if ( this_instance->Monitor != reference_inst->Monitor)
685 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
686 return DMLERR_SYS_ERROR;
687 return DMLERR_INVALIDPARAMETER;
690 /* Check 3 - must supply different callback address */
692 if ( this_instance->CallBack == reference_inst->CallBack)
694 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
695 return DMLERR_SYS_ERROR;
696 return DMLERR_DLL_USAGE;
699 reference_inst = reference_inst->Next_Entry;
701 /* All cleared, add to chain */
703 TRACE("Application Instance checks finished\n");
704 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
705 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0,this_instance)) return DMLERR_SYS_ERROR;
706 reference_inst->Next_Entry = this_instance;
708 *pidInst = this_instance->Instance_id;
709 TRACE("New application instance processing finished OK\n");
711 /* Reinitialisation situation --- FIX */
712 TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
714 if ( !WaitForMutex(handle_mutex) )
716 HeapFree(SystemHeap, 0, this_instance);
717 return DMLERR_SYS_ERROR;
720 if (DDE_Handle_Table_Base == NULL )
722 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance)) return DMLERR_SYS_ERROR;
723 return DMLERR_DLL_USAGE;
725 HeapFree(SystemHeap, 0, this_instance); /* finished - release heap space used as work store */
726 /* can't reinitialise if we have initialised nothing !! */
727 reference_inst = DDE_Handle_Table_Base;
728 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
730 * MS allows initialisation without specifying a callback, should we allow addition of the
731 * callback by a later call to initialise ? - if so this lot will have to change
733 while ( reference_inst->Next_Entry != NULL )
735 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
737 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
739 if ( reference_inst->Client_only )
741 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
743 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
745 if ( ! ( afCmd & APPCMD_CLIENTONLY))
747 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
748 return DMLERR_SYS_ERROR;
749 return DMLERR_DLL_USAGE;
753 /* Check 2 - cannot change monitor modes */
755 if ( this_instance->Monitor != reference_inst->Monitor)
757 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
758 return DMLERR_SYS_ERROR;
759 return DMLERR_DLL_USAGE;
762 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
764 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
766 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
767 return DMLERR_SYS_ERROR;
768 return DMLERR_DLL_USAGE;
772 reference_inst = reference_inst->Next_Entry;
774 if ( reference_inst->Next_Entry == NULL )
776 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
778 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
780 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
781 return DMLERR_SYS_ERROR;
782 return DMLERR_INVALIDPARAMETER;
784 /* All checked - change relevant flags */
786 reference_inst->CBF_Flags = this_instance->CBF_Flags;
787 reference_inst->Client_only = this_instance->Client_only;
788 reference_inst->Monitor_flags = this_instance->Monitor_flags;
789 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
790 return DMLERR_SYS_ERROR;
793 return DMLERR_NO_ERROR;
797 /*****************************************************************
798 * DdeUninitialize16 (DDEML.3)
800 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
802 FIXME(" stub calling DdeUninitialize\n");
803 return (BOOL16)DdeUninitialize( idInst );
807 /*****************************************************************
808 * DdeUninitialize [USER32.119] Frees DDEML resources
811 * idInst [I] Instance identifier
818 BOOL WINAPI DdeUninitialize( DWORD idInst )
820 /* Stage one - check if we have a handle for this instance
822 SECURITY_ATTRIBUTES *s_att= NULL;
823 SECURITY_ATTRIBUTES s_attrib;
824 DDE_HANDLE_ENTRY *this_instance;
825 DDE_HANDLE_ENTRY *reference_inst;
828 if ( DDE_Max_Assigned_Instance == 0 )
830 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
834 if ( !WaitForMutex(handle_mutex) )
836 return DMLERR_SYS_ERROR;
838 TRACE("Handle Mutex created/reserved\n");
839 /* First check instance
841 this_instance = Find_Instance_Entry(idInst);
842 if ( this_instance == NULL )
844 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return FALSE;
846 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
850 FIXME("(%ld): partial stub\n", idInst);
852 /* FIXME ++++++++++++++++++++++++++++++++++++++++++
853 * Needs to de-register all service names
856 /* Free the nodes that were not freed by this instance
857 * and remove the nodes from the list of HSZ nodes.
859 FreeAndRemoveHSZNodes( idInst, this_instance );
861 /* OK now delete the instance handle itself */
863 if ( DDE_Handle_Table_Base == this_instance )
865 /* special case - the first/only entry
867 DDE_Handle_Table_Base = this_instance->Next_Entry;
872 reference_inst = DDE_Handle_Table_Base;
873 while ( reference_inst->Next_Entry != this_instance )
875 reference_inst = this_instance->Next_Entry;
877 reference_inst->Next_Entry = this_instance->Next_Entry;
879 /* release the mutex and the heap entry
881 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE,this_instance))
883 /* should record something here, but nothing left to hang it from !!
891 /*****************************************************************
892 * DdeConnectList16 [DDEML.4]
895 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
896 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
898 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
903 /******************************************************************************
904 * DdeConnectList [USER32.93] Establishes conversation with DDE servers
907 * idInst [I] Instance identifier
908 * hszService [I] Handle to service name string
909 * hszTopic [I] Handle to topic name string
910 * hConvList [I] Handle to conversation list
911 * pCC [I] Pointer to structure with context data
914 * Success: Handle to new conversation list
917 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
918 HCONVLIST hConvList, LPCONVCONTEXT pCC )
920 FIXME("(%ld,%ld,%ld,%ld,%p): stub\n", idInst, hszService, hszTopic,
926 /*****************************************************************
927 * DdeQueryNextServer16 [DDEML.5]
929 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
931 return DdeQueryNextServer(hConvList, hConvPrev);
935 /*****************************************************************
936 * DdeQueryNextServer [USER32.112]
938 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
940 FIXME("(%ld,%ld): stub\n",hConvList,hConvPrev);
944 /*****************************************************************
945 * DdeQueryStringA [USER32.113]
947 *****************************************************************
951 * Vn Date Author Comment
953 * 1.0 Dec 1998 Corel/Macadamian Initial version
954 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
957 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
960 CHAR pString[MAX_BUFFER_LEN];
961 DDE_HANDLE_ENTRY *reference_inst;
964 "(%ld, 0x%lx, %p, %ld, %d): partial stub\n",
970 if ( DDE_Max_Assigned_Instance == 0 )
972 /* Nothing has been initialised - exit now ! */
973 /* needs something for DdeGetLAstError even if the manual doesn't say so */
977 if ( !WaitForMutex(handle_mutex) )
982 TRACE("Handle Mutex created/reserved\n");
984 /* First check instance
986 reference_inst = Find_Instance_Entry(idInst);
987 if ( reference_inst == NULL )
989 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
991 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
996 if( iCodePage == CP_WINANSI )
998 /* If psz is null, we have to return only the length
1004 cchMax = MAX_BUFFER_LEN;
1007 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
1009 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1011 TRACE("returning pointer\n");
1015 /*****************************************************************
1016 * DdeQueryStringW [USER32.114]
1018 *****************************************************************
1022 * Vn Date Author Comment
1024 * 1.0 Dec 1998 Corel/Macadamian Initial version
1028 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1031 WCHAR pString[MAX_BUFFER_LEN];
1035 "(%ld, 0x%lx, %p, %ld, %d): stub\n",
1042 if( iCodePage == CP_WINUNICODE )
1044 /* If psz is null, we have to return only the length
1050 cchMax = MAX_BUFFER_LEN;
1051 /* Note: According to documentation if the psz parameter
1052 * was NULL this API must return the length of the string in bytes.
1054 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1056 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1061 /*****************************************************************
1063 * DdeQueryString16 (DDEML.23)
1065 ******************************************************************
1069 * Vn Date Author Comment
1071 * 1.0 March 1999 K Matthews stub only
1074 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, int codepage)
1076 FIXME("(%ld, 0x%lx, %p, %ld, %d): stub \n",
1086 /*****************************************************************
1087 * DdeDisconnectList (DDEML.6)
1089 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1091 return (BOOL16)DdeDisconnectList(hConvList);
1095 /******************************************************************************
1096 * DdeDisconnectList [USER32.98] Destroys list and terminates conversations
1102 BOOL WINAPI DdeDisconnectList(
1103 HCONVLIST hConvList) /* [in] Handle to conversation list */
1105 FIXME("(%ld): stub\n", hConvList);
1110 /*****************************************************************
1111 * DdeConnect16 (DDEML.7)
1113 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1114 LPCONVCONTEXT16 pCC )
1116 FIXME("empty stub\n" );
1121 /*****************************************************************
1122 * DdeConnect (USER32.92)
1124 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1127 FIXME("(0x%lx,%ld,%ld,%p): stub\n",idInst,hszService,hszTopic,
1133 /*****************************************************************
1134 * DdeDisconnect16 (DDEML.8)
1136 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1138 return (BOOL16)DdeDisconnect( hConv );
1141 /*****************************************************************
1142 * DdeSetUserHandle16 (DDEML.10)
1144 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1146 FIXME("(%ld,%ld,%ld): stub\n",hConv,id, hUser );
1150 /*****************************************************************
1151 * DdeCreateDataHandle16 (DDEML.14)
1153 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
1154 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
1157 return DdeCreateDataHandle(idInst,
1166 /*****************************************************************
1167 * DdeCreateDataHandle (USER32.94)
1169 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
1170 DWORD cbOff, HSZ hszItem, UINT wFmt,
1174 "(%ld,%p,%ld,%ld,0x%lx,%d,%d): stub\n",
1186 /*****************************************************************
1187 * DdeDisconnect (USER32.97)
1189 BOOL WINAPI DdeDisconnect( HCONV hConv )
1191 FIXME("empty stub\n" );
1196 /*****************************************************************
1197 * DdeReconnect (DDEML.37) (USER32.115)
1199 HCONV WINAPI DdeReconnect( HCONV hConv )
1201 FIXME("empty stub\n" );
1206 /*****************************************************************
1207 * DdeCreateStringHandle16 (DDEML.21)
1209 *****************************************************************
1213 * Vn Date Author Comment
1215 * 1.0 ? ? basic stub
1216 * 1.1 June 1999 Keith Matthews amended onward call to supply default
1217 * code page if none supplied by caller
1219 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1223 return DdeCreateStringHandleA( idInst, str, codepage );
1225 TRACE("Default codepage supplied\n");
1226 return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1231 /*****************************************************************
1232 * DdeCreateStringHandleA [USER32.95]
1235 * Success: String handle
1238 *****************************************************************
1242 * Vn Date Author Comment
1244 * 1.0 Dec 1998 Corel/Macadamian Initial version
1245 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1248 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1251 DDE_HANDLE_ENTRY *reference_inst;
1252 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1255 if ( DDE_Max_Assigned_Instance == 0 )
1257 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1261 if ( !WaitForMutex(handle_mutex) )
1263 return DMLERR_SYS_ERROR;
1266 TRACE("Handle Mutex created/reserved\n");
1268 /* First check instance
1270 reference_inst = Find_Instance_Entry(idInst);
1271 if ( reference_inst == NULL )
1273 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1275 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1280 if (codepage==CP_WINANSI)
1282 hsz = GlobalAddAtomA (psz);
1283 /* Save the handle so we know to clean it when
1284 * uninitialize is called.
1286 TRACE("added atom %s with HSZ 0x%lx, \n",debugstr_a(psz),hsz);
1287 InsertHSZNode( hsz, reference_inst );
1288 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1290 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1293 TRACE("Returning pointer\n");
1296 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1298 TRACE("Returning error\n");
1303 /******************************************************************************
1304 * DdeCreateStringHandleW [USER32.96] Creates handle to identify string
1307 * Success: String handle
1310 *****************************************************************
1314 * Vn Date Author Comment
1316 * 1.0 Dec 1998 Corel/Macadamian Initial version
1317 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1320 HSZ WINAPI DdeCreateStringHandleW(
1321 DWORD idInst, /* [in] Instance identifier */
1322 LPCWSTR psz, /* [in] Pointer to string */
1323 INT codepage) /* [in] Code page identifier */
1325 DDE_HANDLE_ENTRY *reference_inst;
1328 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1331 if ( DDE_Max_Assigned_Instance == 0 )
1333 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1337 if ( !WaitForMutex(handle_mutex) )
1339 return DMLERR_SYS_ERROR;
1342 TRACE("CreateString - Handle Mutex created/reserved\n");
1344 /* First check instance
1346 reference_inst = Find_Instance_Entry(idInst);
1347 if ( reference_inst == NULL )
1349 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1351 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1356 FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1358 if (codepage==CP_WINUNICODE)
1360 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1363 hsz = GlobalAddAtomW (psz);
1364 /* Save the handle so we know to clean it when
1365 * uninitialize is called.
1367 InsertHSZNode( hsz, reference_inst );
1368 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1370 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1373 TRACE("Returning pointer\n");
1376 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1378 TRACE("Returning error\n");
1383 /*****************************************************************
1384 * DdeFreeStringHandle16 (DDEML.22)
1386 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1388 FIXME("idInst %ld hsz 0x%lx\n",idInst,hsz);
1389 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1393 /*****************************************************************
1394 * DdeFreeStringHandle (USER32.101)
1395 * RETURNS: success: nonzero
1398 *****************************************************************
1402 * Vn Date Author Comment
1404 * 1.0 Dec 1998 Corel/Macadamian Initial version
1405 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1408 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1410 DDE_HANDLE_ENTRY *reference_inst;
1411 TRACE("(%ld,%ld): \n",idInst,hsz);
1412 if ( DDE_Max_Assigned_Instance == 0 )
1414 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1418 if ( !WaitForMutex(handle_mutex) )
1420 return DMLERR_SYS_ERROR;
1423 TRACE("Handle Mutex created/reserved\n");
1425 /* First check instance
1427 reference_inst = Find_Instance_Entry(idInst);
1428 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1430 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
1431 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1436 /* Remove the node associated with this HSZ.
1438 RemoveHSZNode( hsz , reference_inst);
1439 /* Free the string associated with this HSZ.
1441 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1442 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1446 /*****************************************************************
1447 * DdeFreeDataHandle16 (DDEML.19)
1449 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1451 return (BOOL)DdeFreeDataHandle( hData );
1455 /*****************************************************************
1456 * DdeFreeDataHandle (USER32.100)
1458 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1460 FIXME("empty stub\n" );
1467 /*****************************************************************
1468 * DdeKeepStringHandle16 (DDEML.24)
1470 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1472 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1476 /*****************************************************************
1477 * DdeKeepStringHandle (USER32.108)
1479 * RETURNS: success: nonzero
1482 *****************************************************************
1486 * Vn Date Author Comment
1489 * 1.1 Jun 1999 Keith Matthews First cut implementation
1492 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1495 DDE_HANDLE_ENTRY *reference_inst;
1496 TRACE("(%ld,%ld): \n",idInst,hsz);
1497 if ( DDE_Max_Assigned_Instance == 0 )
1499 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1504 if ( !WaitForMutex(handle_mutex) )
1509 TRACE("Handle Mutex created/reserved\n");
1511 /* First check instance
1513 reference_inst = Find_Instance_Entry(idInst);
1514 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1516 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
1517 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1521 DdeReserveAtom(reference_inst,hsz);
1522 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1527 /*****************************************************************
1528 * DdeClientTransaction16 (DDEML.11)
1530 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1531 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1532 UINT16 wType, DWORD dwTimeout,
1535 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1536 wFmt, wType, dwTimeout, pdwResult );
1540 /*****************************************************************
1541 * DdeClientTransaction (USER32.90)
1543 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1544 HCONV hConv, HSZ hszItem, UINT wFmt,
1545 UINT wType, DWORD dwTimeout,
1548 FIXME("empty stub\n" );
1552 /*****************************************************************
1554 * DdeAbandonTransaction16 (DDEML.12)
1557 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1558 DWORD idTransaction )
1560 FIXME("empty stub\n" );
1565 /*****************************************************************
1567 * DdeAbandonTransaction (USER32.87)
1569 ******************************************************************
1573 * Vn Date Author Comment
1575 * 1.0 March 1999 K Matthews stub only
1577 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1578 DWORD idTransaction )
1580 FIXME("empty stub\n" );
1584 /*****************************************************************
1585 * DdePostAdvise16 [DDEML.13]
1587 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1589 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1593 /******************************************************************************
1594 * DdePostAdvise [USER32.110] Send transaction to DDE callback function.
1600 BOOL WINAPI DdePostAdvise(
1601 DWORD idInst, /* [in] Instance identifier */
1602 HSZ hszTopic, /* [in] Handle to topic name string */
1603 HSZ hszItem) /* [in] Handle to item name string */
1605 FIXME("(%ld,%ld,%ld): stub\n",idInst,hszTopic,hszItem);
1610 /*****************************************************************
1611 * DdeAddData16 (DDEML.15)
1613 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1616 FIXME("empty stub\n" );
1620 /*****************************************************************
1622 * DdeAddData (USER32.89)
1624 ******************************************************************
1628 * Vn Date Author Comment
1630 * 1.0 March 1999 K Matthews stub only
1632 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1635 FIXME("empty stub\n" );
1640 /*****************************************************************
1642 * DdeImpersonateClient (USER32.105)
1644 ******************************************************************
1648 * Vn Date Author Comment
1650 * 1.0 March 1999 K Matthews stub only
1653 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1655 FIXME("empty stub\n" );
1660 /*****************************************************************
1662 * DdeSetQualityOfService (USER32.116)
1664 ******************************************************************
1668 * Vn Date Author Comment
1670 * 1.0 March 1999 K Matthews stub only
1673 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1674 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1676 FIXME("empty stub\n" );
1680 /*****************************************************************
1682 * DdeSetUserHandle (USER32.117)
1684 ******************************************************************
1688 * Vn Date Author Comment
1690 * 1.0 March 1999 K Matthews stub only
1693 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1695 FIXME("empty stub\n" );
1699 /******************************************************************************
1700 * DdeGetData [USER32.102] Copies data from DDE object ot local buffer
1703 * Size of memory object associated with handle
1705 DWORD WINAPI DdeGetData(
1706 HDDEDATA hData, /* [in] Handle to DDE object */
1707 LPBYTE pDst, /* [in] Pointer to destination buffer */
1708 DWORD cbMax, /* [in] Amount of data to copy */
1709 DWORD cbOff) /* [in] Offset to beginning of data */
1711 FIXME("(%ld,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1716 /*****************************************************************
1717 * DdeGetData16 [DDEML.16]
1719 DWORD WINAPI DdeGetData16(
1725 return DdeGetData(hData, pDst, cbMax, cbOff);
1729 /*****************************************************************
1730 * DdeAccessData16 (DDEML.17)
1732 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1734 return DdeAccessData(hData, pcbDataSize);
1737 /*****************************************************************
1738 * DdeAccessData (USER32.88)
1740 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1742 FIXME("(%ld,%p): stub\n", hData, pcbDataSize);
1746 /*****************************************************************
1747 * DdeUnaccessData16 (DDEML.18)
1749 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1751 return DdeUnaccessData(hData);
1754 /*****************************************************************
1755 * DdeUnaccessData (USER32.118)
1757 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1759 FIXME("(0x%lx): stub\n", hData);
1764 /*****************************************************************
1765 * DdeEnableCallback16 (DDEML.26)
1767 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1769 return DdeEnableCallback(idInst, hConv, wCmd);
1772 /*****************************************************************
1773 * DdeEnableCallback (USER32.99)
1775 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1777 FIXME("(%ld, 0x%lx, %d) stub\n", idInst, hConv, wCmd);
1782 /*****************************************************************
1783 * DdeNameService16 (DDEML.27)
1785 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1788 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1792 /******************************************************************************
1793 * DdeNameService [USER32.109] {Un}registers service name of DDE server
1796 * idInst [I] Instance identifier
1797 * hsz1 [I] Handle to service name string
1799 * afCmd [I] Service name flags
1805 *****************************************************************
1809 * Vn Date Author Comment
1812 * 1.1 Apr 1999 Keith Matthews Added trap for non-existent instance (uninitialised instance 0
1813 * used by some MS programs for unfathomable reasons)
1814 * 1.2 May 1999 Keith Matthews Added parameter validation and basic service name handling.
1815 * Still needs callback parts
1818 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1821 ServiceNode* this_service, *reference_service ;
1822 DDE_HANDLE_ENTRY *this_instance;
1823 DDE_HANDLE_ENTRY *reference_inst;
1824 this_service = NULL;
1826 FIXME("(%ld,%ld,%ld,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1828 if ( DDE_Max_Assigned_Instance == 0 )
1830 /* Nothing has been initialised - exit now !
1831 * needs something for DdeGetLastError */
1835 if ( !WaitForMutex(handle_mutex) )
1837 return DMLERR_SYS_ERROR;
1840 TRACE("Handle Mutex created/reserved\n");
1842 /* First check instance
1844 reference_inst = Find_Instance_Entry(idInst);
1845 this_instance = reference_inst;
1846 if (reference_inst == NULL)
1848 TRACE("Instance not found as initialised\n");
1849 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return TRUE;
1850 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1857 /* Illegal, reserved parameter
1859 reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1860 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1861 FIXME("Reserved parameter no-zero !!\n");
1867 * General unregister situation
1869 if ( afCmd != DNS_UNREGISTER )
1871 /* don't know if we should check this but it makes sense
1872 * why supply REGISTER or filter flags if de-registering all
1874 TRACE("General unregister unexpected flags\n");
1875 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1876 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1879 /* Loop to find all registered service and de-register them
1881 if ( reference_inst->ServiceNames == NULL )
1883 /* None to unregister !!
1885 TRACE("General de-register - nothing registered\n");
1886 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1887 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1891 this_service = reference_inst->ServiceNames;
1892 while ( this_service->next != NULL)
1894 TRACE("general deregister - iteration\n");
1895 reference_service = this_service;
1896 this_service = this_service->next;
1897 DdeReleaseAtom(reference_inst,reference_service->hsz);
1898 HeapFree(SystemHeap, 0, reference_service); /* finished - release heap space used as work store */
1900 DdeReleaseAtom(reference_inst,this_service->hsz);
1901 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space used as work store */
1902 reference_inst->ServiceNames = NULL;
1903 TRACE("General de-register - finished\n");
1905 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1908 TRACE("Specific name action detected\n");
1909 if ( afCmd & DNS_REGISTER )
1911 /* Register new service name
1914 this_service = Find_Service_Name( hsz1, reference_inst );
1916 ERR("Trying to register already registered service!\n");
1919 TRACE("Adding service name\n");
1921 DdeReserveAtom(reference_inst, hsz1);
1923 this_service = (ServiceNode*)HeapAlloc( SystemHeap, 0, sizeof(ServiceNode) );
1924 this_service->hsz = hsz1;
1925 this_service->FilterOn = TRUE;
1927 this_service->next = reference_inst->ServiceNames;
1928 reference_inst->ServiceNames = this_service;
1931 if ( afCmd & DNS_UNREGISTER )
1933 /* De-register service name
1936 ServiceNode **pServiceNode = &reference_inst->ServiceNames;
1937 while ( *pServiceNode && (*pServiceNode)->hsz != hsz1 )
1938 pServiceNode = &(*pServiceNode)->next;
1940 this_service = *pServiceNode;
1941 if ( !this_service )
1942 ERR("Trying to de-register unregistered service!\n");
1945 *pServiceNode = this_service->next;
1946 DdeReleaseAtom(reference_inst,this_service->hsz);
1947 HeapFree(SystemHeap, 0, this_service);
1950 if ( afCmd & DNS_FILTERON )
1952 /* Set filter flags on to hold notifications of connection
1954 * test coded this way as this is the default setting
1956 this_service = Find_Service_Name( hsz1, reference_inst );
1957 if ( !this_service )
1959 /* trying to filter where no service names !!
1961 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1962 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1966 this_service->FilterOn = TRUE;
1969 if ( afCmd & DNS_FILTEROFF )
1971 /* Set filter flags on to hold notifications of connection
1973 this_service = Find_Service_Name( hsz1, reference_inst );
1974 if ( !this_service )
1976 /* trying to filter where no service names !!
1978 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1979 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1983 this_service->FilterOn = FALSE;
1986 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1991 /*****************************************************************
1992 * DdeGetLastError16 (DDEML.20)
1994 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1996 return (UINT16)DdeGetLastError( idInst );
2000 /******************************************************************************
2001 * DdeGetLastError [USER32.103] Gets most recent error code
2004 * idInst [I] Instance identifier
2009 *****************************************************************
2013 * Vn Date Author Comment
2016 * 1.1 Apr 1999 Keith Matthews Added response for non-existent instance (uninitialised instance 0
2017 * used by some MS programs for unfathomable reasons)
2018 * 1.2 May 1999 Keith Matthews Added interrogation of Last_Error for instance handle where found.
2021 UINT WINAPI DdeGetLastError( DWORD idInst )
2024 DDE_HANDLE_ENTRY *reference_inst;
2026 FIXME("(%ld): stub\n",idInst);
2028 if ( DDE_Max_Assigned_Instance == 0 )
2030 /* Nothing has been initialised - exit now ! */
2031 return DMLERR_DLL_NOT_INITIALIZED;
2034 if ( !WaitForMutex(handle_mutex) )
2036 return DMLERR_SYS_ERROR;
2039 TRACE("Handle Mutex created/reserved\n");
2041 /* First check instance
2043 reference_inst = Find_Instance_Entry(idInst);
2044 if (reference_inst == NULL)
2046 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
2047 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2048 return DMLERR_DLL_NOT_INITIALIZED;
2051 error_code = reference_inst->Last_Error;
2052 reference_inst->Last_Error = 0;
2053 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
2058 /*****************************************************************
2059 * DdeCmpStringHandles16 (DDEML.36)
2061 int WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2063 return DdeCmpStringHandles(hsz1, hsz2);
2066 /*****************************************************************
2067 * DdeCmpStringHandles (USER32.91)
2069 * Compares the value of two string handles. This comparison is
2070 * not case sensitive.
2073 * -1 The value of hsz1 is zero or less than hsz2
2074 * 0 The values of hsz 1 and 2 are the same or both zero.
2075 * 1 The value of hsz2 is zero of less than hsz1
2077 int WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2079 CHAR psz1[MAX_BUFFER_LEN];
2080 CHAR psz2[MAX_BUFFER_LEN];
2084 TRACE("handle 1, handle 2\n" );
2086 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2087 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2088 /* Make sure we found both strings.
2090 if( ret1 == 0 && ret2 == 0 )
2092 /* If both are not found, return both "zero strings".
2096 else if( ret1 == 0 )
2098 /* If hsz1 is a not found, return hsz1 is "zero string".
2102 else if( ret2 == 0 )
2104 /* If hsz2 is a not found, return hsz2 is "zero string".
2110 /* Compare the two strings we got ( case insensitive ).
2112 ret = strcasecmp( psz1, psz2 );
2113 /* Since strcmp returns any number smaller than
2114 * 0 when the first string is found to be less than
2115 * the second one we must make sure we are returning
2116 * the proper values.
2131 /*****************************************************************
2132 * PackDDElParam (USER32.414)
2138 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2145 /*****************************************************************
2146 * UnpackDDElParam (USER32.562)
2152 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
2153 UINT *uiLo, UINT *uiHi)
2160 /*****************************************************************
2161 * FreeDDElParam (USER32.204)
2167 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
2173 /*****************************************************************
2174 * ReuseDDElParam (USER32.446)
2177 UINT WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2178 UINT uiLi, UINT uiHi)
2184 /******************************************************************
2185 * DdeQueryConvInfo16 (DDEML.9)
2188 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2195 /******************************************************************
2196 * DdeQueryConvInfo (USER32.111)
2199 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)