4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Len White
6 * Copyright 1999 Keith Matthews
9 /* Only empty stubs for now */
21 #include "debugtools.h"
24 DEFAULT_DEBUG_CHANNEL(ddeml);
26 /* Has defined in atom.c file.
28 #define MAX_ATOM_LEN 255
30 /* Maximum buffer size ( including the '\0' ).
32 #define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1)
36 LPVOID lpSecurityDescriptor;
38 } SECURITY_ATTRIBUTES; */
40 /* This is a simple list to keep track of the strings created
41 * by DdeCreateStringHandle. The list is used to free
42 * the strings whenever DdeUninitialize is called.
43 * This mechanism is not complete and does not handle multiple instances.
44 * Most of the DDE API use a DWORD parameter indicating which instance
45 * of a given program is calling them. The API are supposed to
46 * associate the data to the instance that created it.
48 typedef struct tagHSZNode HSZNode;
56 typedef struct tagServiceNode ServiceNode;
63 typedef struct DDE_HANDLE_ENTRY {
64 BOOL16 Monitor; /* have these two as full Booleans cos they'll be tested frequently */
65 BOOL16 Client_only; /* bit wasteful of space but it will be faster */
66 BOOL16 Unicode; /* Flag to indicate Win32 API used to initialise */
67 BOOL16 Win16; /* flag to indicate Win16 API used to initialize */
68 DWORD Instance_id; /* needed to track monitor usage */
69 struct DDE_HANDLE_ENTRY *Next_Entry;
74 UINT Txn_count; /* count transactions open to simplify closure */
76 ServiceNode* ServiceNames;
79 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
80 static DWORD DDE_Max_Assigned_Instance = 0; /* OK for present, may have to worry about wrap-around later */
81 static const char *DDEInstanceAccess = "DDEMaxInstance";
82 static const char *DDEHandleAccess = "DDEHandleAccess";
83 static HANDLE inst_count_mutex = 0;
84 static HANDLE handle_mutex = 0;
90 /******************************************************************************
91 * RemoveHSZNodes (INTERNAL)
93 * Remove a node from the list of HSZ nodes.
95 ******************************************************************************
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 )
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.
135 pPrev->next = pCurrent->next;
137 /* Destroy this node.
142 /* Save the previous node pointer.
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 ******************************************************************************
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 ******************************************************************************
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 )
197 HSZNode* pNew = NULL;
198 /* Create a new node for this HSZ.
200 pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
203 /* Set the handle value.
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 ******************************************************************************
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");
252 /*****************************************************************************
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 ******************************************************************************
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");
285 /******************************************************************************
286 * Release_reserved_mutex
288 * generic routine to release a reserved mutex
291 ******************************************************************************
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
299 * 1.2 Aug 1999 Jürgen Schmied Corrected error handling
302 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i ,
303 DDE_HANDLE_ENTRY *this_instance)
305 if (!ReleaseMutex(mutex))
307 ERR("ReleaseMutex failed - %s mutex %li\n",mutex_name,GetLastError());
308 HeapFree(GetProcessHeap(), 0, this_instance);
309 if ( release_handle_m )
311 ReleaseMutex(handle_mutex);
313 return DMLERR_SYS_ERROR;
315 if ( release_this_i )
317 HeapFree(GetProcessHeap(), 0, this_instance);
319 return DMLERR_NO_ERROR;
322 /******************************************************************************
325 * generic routine to wait for the mutex
328 ******************************************************************************
332 * Vn Date Author Comment
334 * 1.0 Aug 1999 Juergen Schmied Initial version
337 static BOOL WaitForMutex (HANDLE mutex)
341 result = WaitForSingleObject(mutex,1000);
343 /* both errors should never occur */
344 if (WAIT_TIMEOUT == result)
346 ERR("WaitForSingleObject timed out\n");
350 if (WAIT_FAILED == result)
352 ERR("WaitForSingleObject failed - error %li\n", GetLastError());
357 /******************************************************************************
358 * IncrementInstanceId
360 * generic routine to increment the max instance Id and allocate a new application instance
362 ******************************************************************************
366 * Vn Date Author Comment
368 * 1.0 Jan 1999 Keith Matthews Initial version
371 DWORD IncrementInstanceId( DDE_HANDLE_ENTRY *this_instance)
373 SECURITY_ATTRIBUTES s_attrib;
375 /* Need to set up Mutex in case it is not already present */
376 /* increment handle count & get value */
377 if ( !inst_count_mutex )
379 s_attrib.bInheritHandle = TRUE;
380 s_attrib.lpSecurityDescriptor = NULL;
381 s_attrib.nLength = sizeof(s_attrib);
382 inst_count_mutex = CreateMutexA(&s_attrib,0,DDEInstanceAccess); /* 1st time through */
384 if ( inst_count_mutex )
386 if ( !WaitForMutex(inst_count_mutex) )
388 return DMLERR_SYS_ERROR;
392 ERR("CreateMutex failed - inst_count %li\n",GetLastError());
393 Release_reserved_mutex (handle_mutex,"handle_mutex",0,1,this_instance);
394 return DMLERR_SYS_ERROR;
396 DDE_Max_Assigned_Instance++;
397 this_instance->Instance_id = DDE_Max_Assigned_Instance;
398 TRACE("New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
399 if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0,this_instance)) return DMLERR_SYS_ERROR;
400 return DMLERR_NO_ERROR;
403 /******************************************************************************
404 * FindNotifyMonitorCallbacks
406 * Routine to find instances that need to be notified via their callback
407 * of some event they are monitoring
409 ******************************************************************************
413 * Vn Date Author Comment
415 * 1.0 May 1999 Keith Matthews Initial Version
419 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
421 DDE_HANDLE_ENTRY *InstanceHandle;
422 InstanceHandle = DDE_Handle_Table_Base;
423 while ( InstanceHandle != NULL )
425 if ( (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
427 /* Found an instance registered as monitor and is not ourselves
428 * use callback to notify where appropriate
431 InstanceHandle = InstanceHandle->Next_Entry;
435 /******************************************************************************
438 * Routine to make an extra Add on an atom to reserve it a bit longer
440 ******************************************************************************
444 * Vn Date Author Comment
446 * 1.0 Jun 1999 Keith Matthews Initial Version
450 static void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
452 if ( reference_inst->Unicode)
454 WCHAR SNameBuffer[MAX_BUFFER_LEN];
455 GlobalGetAtomNameW(hsz,SNameBuffer,MAX_BUFFER_LEN);
456 GlobalAddAtomW(SNameBuffer);
458 CHAR SNameBuffer[MAX_BUFFER_LEN];
459 GlobalGetAtomNameA(hsz,SNameBuffer,MAX_BUFFER_LEN);
460 GlobalAddAtomA(SNameBuffer);
465 /******************************************************************************
468 * Routine to make a delete on an atom to release it a bit sooner
470 ******************************************************************************
474 * Vn Date Author Comment
476 * 1.0 Jun 1999 Keith Matthews Initial Version
480 static void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
482 GlobalDeleteAtom( hsz );
485 /******************************************************************************
486 * DdeInitialize16 (DDEML.2)
488 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
489 DWORD afCmd, DWORD ulRes)
491 TRACE("DdeInitialize16 called - calling DdeInitializeA\n");
492 return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
497 /******************************************************************************
498 * DdeInitializeA (USER32.@)
500 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
501 DWORD afCmd, DWORD ulRes )
503 TRACE("DdeInitializeA called - calling DdeInitializeW\n");
504 return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
508 /******************************************************************************
509 * DdeInitializeW [USER32.@]
510 * Registers an application with the DDEML
513 * pidInst [I] Pointer to instance identifier
514 * pfnCallback [I] Pointer to callback function
515 * afCmd [I] Set of command and filter flags
519 * Success: DMLERR_NO_ERROR
520 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
522 ******************************************************************************
526 * Vn Date Author Comment
528 * 1.0 Pre 1998 Alexandre/Len Initial Stub
529 * 1.1 Jan 1999 Keith Matthews Initial (near-)complete version
530 * 1.2 Mar 1999 Keith Matthews Corrected Heap handling, CreateMutex failure handling
533 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
534 DWORD afCmd, DWORD ulRes )
537 /* probably not really capable of handling multiple processes, but should handle
538 * multiple instances within one process */
540 SECURITY_ATTRIBUTES *s_att= NULL;
541 SECURITY_ATTRIBUTES s_attrib;
543 DDE_HANDLE_ENTRY *this_instance;
544 DDE_HANDLE_ENTRY *reference_inst;
549 ERR("Reserved value not zero? What does this mean?\n");
550 FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
552 /* trap this and no more until we know more */
553 return DMLERR_NO_ERROR;
557 /* this one may be wrong - MS dll seems to accept the condition,
558 leave this until we find out more !! */
561 /* can't set up the instance with nothing to act as a callback */
562 TRACE("No callback provided\n");
563 return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
566 /* grab enough heap for one control struct - not really necessary for re-initialise
567 * but allows us to use same validation routines */
568 this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( GetProcessHeap(), 0, sizeof(DDE_HANDLE_ENTRY) );
569 if ( this_instance == NULL )
571 /* catastrophe !! warn user & abort */
572 ERR("Instance create failed - out of memory\n");
573 return DMLERR_SYS_ERROR;
575 this_instance->Next_Entry = NULL;
576 this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
578 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
580 this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
581 this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
582 this_instance->CallBack=*pfnCallback;
583 this_instance->Txn_count=0;
584 this_instance->Unicode = TRUE;
585 this_instance->Win16 = FALSE;
586 this_instance->Node_list = NULL; /* node will be added later */
587 this_instance->Monitor_flags = afCmd & MF_MASK;
588 this_instance->ServiceNames = NULL;
590 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
592 this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
594 if ( ! this_instance->Client_only )
597 /* Check for other way of setting Client-only !! */
599 this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
600 ==CBF_FAIL_ALLSVRXACTIONS;
603 TRACE("instance created - checking validity \n");
605 if( *pidInst == 0 ) {
606 /* Initialisation of new Instance Identifier */
607 TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
608 if ( DDE_Max_Assigned_Instance == 0 )
610 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
611 /* Need to set up Mutex in case it is not already present */
612 s_att->bInheritHandle = TRUE;
613 s_att->lpSecurityDescriptor = NULL;
614 s_att->nLength = sizeof(s_att);
615 handle_mutex = CreateMutexA(s_att,0,DDEHandleAccess);
616 if ( !handle_mutex ) {
617 ERR("CreateMutex failed - handle list %li\n",GetLastError());
618 HeapFree(GetProcessHeap(), 0, this_instance);
619 return DMLERR_SYS_ERROR;
622 if ( !WaitForMutex(handle_mutex) )
624 return DMLERR_SYS_ERROR;
627 TRACE("Handle Mutex created/reserved\n");
628 if (DDE_Handle_Table_Base == NULL )
630 /* can't be another instance in this case, assign to the base pointer */
631 DDE_Handle_Table_Base= this_instance;
633 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
635 * ------------------------------- NOTE NOTE NOTE --------------------------
637 * the manual is not clear if this condition
638 * applies to the first call to DdeInitialize from an application, or the
639 * first call for a given callback !!!
642 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
643 TRACE("First application instance detected OK\n");
644 /* allocate new instance ID */
645 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
648 /* really need to chain the new one in to the latest here, but after checking conditions
649 * such as trying to start a conversation from an application trying to monitor */
650 reference_inst = DDE_Handle_Table_Base;
651 TRACE("Subsequent application instance - starting checks\n");
652 while ( reference_inst->Next_Entry != NULL )
655 * This set of tests will work if application uses same instance Id
656 * at application level once allocated - which is what manual implies
657 * should happen. If someone tries to be
658 * clever (lazy ?) it will fail to pick up that later calls are for
659 * the same application - should we trust them ?
661 if ( this_instance->Instance_id == reference_inst->Instance_id)
663 /* Check 1 - must be same Client-only state */
665 if ( this_instance->Client_only != reference_inst->Client_only)
667 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
668 return DMLERR_SYS_ERROR;
669 return DMLERR_DLL_USAGE;
672 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
674 if ( this_instance->Monitor != reference_inst->Monitor)
676 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
677 return DMLERR_SYS_ERROR;
678 return DMLERR_INVALIDPARAMETER;
681 /* Check 3 - must supply different callback address */
683 if ( this_instance->CallBack == reference_inst->CallBack)
685 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
686 return DMLERR_SYS_ERROR;
687 return DMLERR_DLL_USAGE;
690 reference_inst = reference_inst->Next_Entry;
692 /* All cleared, add to chain */
694 TRACE("Application Instance checks finished\n");
695 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
696 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0,this_instance)) return DMLERR_SYS_ERROR;
697 reference_inst->Next_Entry = this_instance;
699 *pidInst = this_instance->Instance_id;
700 TRACE("New application instance processing finished OK\n");
702 /* Reinitialisation situation --- FIX */
703 TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
705 if ( !WaitForMutex(handle_mutex) )
707 HeapFree(GetProcessHeap(), 0, this_instance);
708 return DMLERR_SYS_ERROR;
711 if (DDE_Handle_Table_Base == NULL )
713 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance)) return DMLERR_SYS_ERROR;
714 return DMLERR_DLL_USAGE;
716 HeapFree(GetProcessHeap(), 0, this_instance); /* finished - release heap space used as work store */
717 /* can't reinitialise if we have initialised nothing !! */
718 reference_inst = DDE_Handle_Table_Base;
719 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
721 * MS allows initialisation without specifying a callback, should we allow addition of the
722 * callback by a later call to initialise ? - if so this lot will have to change
724 while ( reference_inst->Next_Entry != NULL )
726 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
728 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
730 if ( reference_inst->Client_only )
732 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
734 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
736 if ( ! ( afCmd & APPCMD_CLIENTONLY))
738 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
739 return DMLERR_SYS_ERROR;
740 return DMLERR_DLL_USAGE;
744 /* Check 2 - cannot change monitor modes */
746 if ( this_instance->Monitor != reference_inst->Monitor)
748 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
749 return DMLERR_SYS_ERROR;
750 return DMLERR_DLL_USAGE;
753 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
755 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
757 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
758 return DMLERR_SYS_ERROR;
759 return DMLERR_DLL_USAGE;
763 reference_inst = reference_inst->Next_Entry;
765 if ( reference_inst->Next_Entry == NULL )
767 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
769 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
771 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
772 return DMLERR_SYS_ERROR;
773 return DMLERR_INVALIDPARAMETER;
775 /* All checked - change relevant flags */
777 reference_inst->CBF_Flags = this_instance->CBF_Flags;
778 reference_inst->Client_only = this_instance->Client_only;
779 reference_inst->Monitor_flags = this_instance->Monitor_flags;
780 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
781 return DMLERR_SYS_ERROR;
784 return DMLERR_NO_ERROR;
788 /*****************************************************************
789 * DdeUninitialize16 (DDEML.3)
791 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
793 FIXME(" stub calling DdeUninitialize\n");
794 return (BOOL16)DdeUninitialize( idInst );
798 /*****************************************************************
799 * DdeUninitialize [USER32.@] Frees DDEML resources
802 * idInst [I] Instance identifier
809 BOOL WINAPI DdeUninitialize( DWORD idInst )
811 /* Stage one - check if we have a handle for this instance
813 SECURITY_ATTRIBUTES *s_att= NULL;
814 SECURITY_ATTRIBUTES s_attrib;
815 DDE_HANDLE_ENTRY *this_instance;
816 DDE_HANDLE_ENTRY *reference_inst;
819 if ( DDE_Max_Assigned_Instance == 0 )
821 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
825 if ( !WaitForMutex(handle_mutex) )
827 return DMLERR_SYS_ERROR;
829 TRACE("Handle Mutex created/reserved\n");
830 /* First check instance
832 this_instance = Find_Instance_Entry(idInst);
833 if ( this_instance == NULL )
835 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return FALSE;
837 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
841 FIXME("(%ld): partial stub\n", idInst);
843 /* FIXME ++++++++++++++++++++++++++++++++++++++++++
844 * Needs to de-register all service names
847 /* Free the nodes that were not freed by this instance
848 * and remove the nodes from the list of HSZ nodes.
850 FreeAndRemoveHSZNodes( idInst, this_instance );
852 /* OK now delete the instance handle itself */
854 if ( DDE_Handle_Table_Base == this_instance )
856 /* special case - the first/only entry
858 DDE_Handle_Table_Base = this_instance->Next_Entry;
863 reference_inst = DDE_Handle_Table_Base;
864 while ( reference_inst->Next_Entry != this_instance )
866 reference_inst = this_instance->Next_Entry;
868 reference_inst->Next_Entry = this_instance->Next_Entry;
870 /* release the mutex and the heap entry
872 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE,this_instance))
874 /* should record something here, but nothing left to hang it from !!
882 /*****************************************************************
883 * DdeConnectList16 [DDEML.4]
886 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
887 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
889 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
894 /******************************************************************************
895 * DdeConnectList [USER32.@] Establishes conversation with DDE servers
898 * idInst [I] Instance identifier
899 * hszService [I] Handle to service name string
900 * hszTopic [I] Handle to topic name string
901 * hConvList [I] Handle to conversation list
902 * pCC [I] Pointer to structure with context data
905 * Success: Handle to new conversation list
908 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
909 HCONVLIST hConvList, LPCONVCONTEXT pCC )
911 FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
917 /*****************************************************************
918 * DdeQueryNextServer16 [DDEML.5]
920 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
922 return DdeQueryNextServer(hConvList, hConvPrev);
926 /*****************************************************************
927 * DdeQueryNextServer [USER32.@]
929 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
931 FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
935 /*****************************************************************
936 * DdeQueryStringA [USER32.@]
938 *****************************************************************
942 * Vn Date Author Comment
944 * 1.0 Dec 1998 Corel/Macadamian Initial version
945 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
948 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
951 CHAR pString[MAX_BUFFER_LEN];
952 DDE_HANDLE_ENTRY *reference_inst;
955 "(%ld, 0x%x, %p, %ld, %d): partial stub\n",
961 if ( DDE_Max_Assigned_Instance == 0 )
963 /* Nothing has been initialised - exit now ! */
964 /* needs something for DdeGetLAstError even if the manual doesn't say so */
968 if ( !WaitForMutex(handle_mutex) )
973 TRACE("Handle Mutex created/reserved\n");
975 /* First check instance
977 reference_inst = Find_Instance_Entry(idInst);
978 if ( reference_inst == NULL )
980 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
982 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
987 if( iCodePage == CP_WINANSI )
989 /* If psz is null, we have to return only the length
995 cchMax = MAX_BUFFER_LEN;
998 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
1000 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1002 TRACE("returning pointer\n");
1006 /*****************************************************************
1007 * DdeQueryStringW [USER32.@]
1009 *****************************************************************
1013 * Vn Date Author Comment
1015 * 1.0 Dec 1998 Corel/Macadamian Initial version
1019 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1022 WCHAR pString[MAX_BUFFER_LEN];
1026 "(%ld, 0x%x, %p, %ld, %d): stub\n",
1033 if( iCodePage == CP_WINUNICODE )
1035 /* If psz is null, we have to return only the length
1041 cchMax = MAX_BUFFER_LEN;
1042 /* Note: According to documentation if the psz parameter
1043 * was NULL this API must return the length of the string in bytes.
1045 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1047 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1052 /*****************************************************************
1054 * DdeQueryString16 (DDEML.23)
1056 ******************************************************************
1060 * Vn Date Author Comment
1062 * 1.0 March 1999 K Matthews stub only
1065 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, INT16 codepage)
1067 FIXME("(%ld, 0x%x, %p, %ld, %d): stub \n",
1077 /*****************************************************************
1078 * DdeDisconnectList (DDEML.6)
1080 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1082 return (BOOL16)DdeDisconnectList(hConvList);
1086 /******************************************************************************
1087 * DdeDisconnectList [USER32.@] Destroys list and terminates conversations
1093 BOOL WINAPI DdeDisconnectList(
1094 HCONVLIST hConvList) /* [in] Handle to conversation list */
1096 FIXME("(%d): stub\n", hConvList);
1101 /*****************************************************************
1102 * DdeConnect16 (DDEML.7)
1104 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1105 LPCONVCONTEXT16 pCC )
1107 FIXME("empty stub\n" );
1112 /*****************************************************************
1113 * DdeConnect (USER32.@)
1115 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1118 FIXME("(0x%lx,%d,%d,%p): stub\n",idInst,hszService,hszTopic,
1124 /*****************************************************************
1125 * DdeDisconnect16 (DDEML.8)
1127 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1129 return (BOOL16)DdeDisconnect( hConv );
1132 /*****************************************************************
1133 * DdeSetUserHandle16 (DDEML.10)
1135 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1137 FIXME("(%d,%ld,%ld): stub\n",hConv,id, hUser );
1141 /*****************************************************************
1142 * DdeCreateDataHandle16 (DDEML.14)
1144 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
1145 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
1148 return DdeCreateDataHandle(idInst,
1157 /*****************************************************************
1158 * DdeCreateDataHandle (USER32.@)
1160 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
1161 DWORD cbOff, HSZ hszItem, UINT wFmt,
1165 "(%ld,%p,%ld,%ld,0x%x,%d,%d): stub\n",
1177 /*****************************************************************
1178 * DdeDisconnect (USER32.@)
1180 BOOL WINAPI DdeDisconnect( HCONV hConv )
1182 FIXME("empty stub\n" );
1187 /*****************************************************************
1188 * DdeReconnect (DDEML.37) (USER32.@)
1190 HCONV WINAPI DdeReconnect( HCONV hConv )
1192 FIXME("empty stub\n" );
1197 /*****************************************************************
1198 * DdeCreateStringHandle16 (DDEML.21)
1200 *****************************************************************
1204 * Vn Date Author Comment
1206 * 1.0 ? ? basic stub
1207 * 1.1 June 1999 Keith Matthews amended onward call to supply default
1208 * code page if none supplied by caller
1210 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1214 return DdeCreateStringHandleA( idInst, str, codepage );
1216 TRACE("Default codepage supplied\n");
1217 return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1222 /*****************************************************************
1223 * DdeCreateStringHandleA [USER32.@]
1226 * Success: String handle
1229 *****************************************************************
1233 * Vn Date Author Comment
1235 * 1.0 Dec 1998 Corel/Macadamian Initial version
1236 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1239 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1242 DDE_HANDLE_ENTRY *reference_inst;
1243 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1246 if ( DDE_Max_Assigned_Instance == 0 )
1248 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1252 if ( !WaitForMutex(handle_mutex) )
1254 return DMLERR_SYS_ERROR;
1257 TRACE("Handle Mutex created/reserved\n");
1259 /* First check instance
1261 reference_inst = Find_Instance_Entry(idInst);
1262 if ( reference_inst == NULL )
1264 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1266 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1271 if (codepage==CP_WINANSI)
1273 hsz = GlobalAddAtomA (psz);
1274 /* Save the handle so we know to clean it when
1275 * uninitialize is called.
1277 TRACE("added atom %s with HSZ 0x%x, \n",debugstr_a(psz),hsz);
1278 InsertHSZNode( hsz, reference_inst );
1279 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1281 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1284 TRACE("Returning pointer\n");
1287 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1289 TRACE("Returning error\n");
1294 /******************************************************************************
1295 * DdeCreateStringHandleW [USER32.@] Creates handle to identify string
1298 * Success: String handle
1301 *****************************************************************
1305 * Vn Date Author Comment
1307 * 1.0 Dec 1998 Corel/Macadamian Initial version
1308 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1311 HSZ WINAPI DdeCreateStringHandleW(
1312 DWORD idInst, /* [in] Instance identifier */
1313 LPCWSTR psz, /* [in] Pointer to string */
1314 INT codepage) /* [in] Code page identifier */
1316 DDE_HANDLE_ENTRY *reference_inst;
1319 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1322 if ( DDE_Max_Assigned_Instance == 0 )
1324 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1328 if ( !WaitForMutex(handle_mutex) )
1330 return DMLERR_SYS_ERROR;
1333 TRACE("CreateString - Handle Mutex created/reserved\n");
1335 /* First check instance
1337 reference_inst = Find_Instance_Entry(idInst);
1338 if ( reference_inst == NULL )
1340 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1342 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1347 FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1349 if (codepage==CP_WINUNICODE)
1351 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1354 hsz = GlobalAddAtomW (psz);
1355 /* Save the handle so we know to clean it when
1356 * uninitialize is called.
1358 InsertHSZNode( hsz, reference_inst );
1359 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1361 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1364 TRACE("Returning pointer\n");
1367 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1369 TRACE("Returning error\n");
1374 /*****************************************************************
1375 * DdeFreeStringHandle16 (DDEML.22)
1377 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1379 FIXME("idInst %ld hsz 0x%x\n",idInst,hsz);
1380 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1384 /*****************************************************************
1385 * DdeFreeStringHandle (USER32.@)
1386 * RETURNS: success: nonzero
1389 *****************************************************************
1393 * Vn Date Author Comment
1395 * 1.0 Dec 1998 Corel/Macadamian Initial version
1396 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1399 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1401 DDE_HANDLE_ENTRY *reference_inst;
1402 TRACE("(%ld,%d): \n",idInst,hsz);
1403 if ( DDE_Max_Assigned_Instance == 0 )
1405 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1409 if ( !WaitForMutex(handle_mutex) )
1411 return DMLERR_SYS_ERROR;
1414 TRACE("Handle Mutex created/reserved\n");
1416 /* First check instance
1418 reference_inst = Find_Instance_Entry(idInst);
1419 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1421 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
1422 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1427 /* Remove the node associated with this HSZ.
1429 RemoveHSZNode( hsz , reference_inst);
1430 /* Free the string associated with this HSZ.
1432 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1433 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1437 /*****************************************************************
1438 * DdeFreeDataHandle16 (DDEML.19)
1440 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1442 return (BOOL)DdeFreeDataHandle( hData );
1446 /*****************************************************************
1447 * DdeFreeDataHandle (USER32.@)
1449 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1451 FIXME("empty stub\n" );
1458 /*****************************************************************
1459 * DdeKeepStringHandle16 (DDEML.24)
1461 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1463 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1467 /*****************************************************************
1468 * DdeKeepStringHandle (USER32.@)
1470 * RETURNS: success: nonzero
1473 *****************************************************************
1477 * Vn Date Author Comment
1480 * 1.1 Jun 1999 Keith Matthews First cut implementation
1483 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1486 DDE_HANDLE_ENTRY *reference_inst;
1487 TRACE("(%ld,%d): \n",idInst,hsz);
1488 if ( DDE_Max_Assigned_Instance == 0 )
1490 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1495 if ( !WaitForMutex(handle_mutex) )
1500 TRACE("Handle Mutex created/reserved\n");
1502 /* First check instance
1504 reference_inst = Find_Instance_Entry(idInst);
1505 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1507 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
1508 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1512 DdeReserveAtom(reference_inst,hsz);
1513 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1518 /*****************************************************************
1519 * DdeClientTransaction16 (DDEML.11)
1521 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1522 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1523 UINT16 wType, DWORD dwTimeout,
1526 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1527 wFmt, wType, dwTimeout, pdwResult );
1531 /*****************************************************************
1532 * DdeClientTransaction (USER32.@)
1534 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1535 HCONV hConv, HSZ hszItem, UINT wFmt,
1536 UINT wType, DWORD dwTimeout,
1539 FIXME("empty stub\n" );
1543 /*****************************************************************
1545 * DdeAbandonTransaction16 (DDEML.12)
1548 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1549 DWORD idTransaction )
1551 FIXME("empty stub\n" );
1556 /*****************************************************************
1558 * DdeAbandonTransaction (USER32.@)
1560 ******************************************************************
1564 * Vn Date Author Comment
1566 * 1.0 March 1999 K Matthews stub only
1568 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1569 DWORD idTransaction )
1571 FIXME("empty stub\n" );
1575 /*****************************************************************
1576 * DdePostAdvise16 [DDEML.13]
1578 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1580 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1584 /******************************************************************************
1585 * DdePostAdvise [USER32.@] Send transaction to DDE callback function.
1591 BOOL WINAPI DdePostAdvise(
1592 DWORD idInst, /* [in] Instance identifier */
1593 HSZ hszTopic, /* [in] Handle to topic name string */
1594 HSZ hszItem) /* [in] Handle to item name string */
1596 FIXME("(%ld,%d,%d): stub\n",idInst,hszTopic,hszItem);
1601 /*****************************************************************
1602 * DdeAddData16 (DDEML.15)
1604 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1607 FIXME("empty stub\n" );
1611 /*****************************************************************
1613 * DdeAddData (USER32.@)
1615 ******************************************************************
1619 * Vn Date Author Comment
1621 * 1.0 March 1999 K Matthews stub only
1623 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1626 FIXME("empty stub\n" );
1631 /*****************************************************************
1633 * DdeImpersonateClient (USER32.@)
1635 ******************************************************************
1639 * Vn Date Author Comment
1641 * 1.0 March 1999 K Matthews stub only
1644 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1646 FIXME("empty stub\n" );
1651 /*****************************************************************
1653 * DdeSetQualityOfService (USER32.@)
1655 ******************************************************************
1659 * Vn Date Author Comment
1661 * 1.0 March 1999 K Matthews stub only
1664 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1665 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1667 FIXME("empty stub\n" );
1671 /*****************************************************************
1673 * DdeSetUserHandle (USER32.@)
1675 ******************************************************************
1679 * Vn Date Author Comment
1681 * 1.0 March 1999 K Matthews stub only
1684 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1686 FIXME("empty stub\n" );
1690 /******************************************************************************
1691 * DdeGetData [USER32.@] Copies data from DDE object to local buffer
1694 * Size of memory object associated with handle
1696 DWORD WINAPI DdeGetData(
1697 HDDEDATA hData, /* [in] Handle to DDE object */
1698 LPBYTE pDst, /* [in] Pointer to destination buffer */
1699 DWORD cbMax, /* [in] Amount of data to copy */
1700 DWORD cbOff) /* [in] Offset to beginning of data */
1702 FIXME("(%d,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1707 /*****************************************************************
1708 * DdeGetData16 [DDEML.16]
1710 DWORD WINAPI DdeGetData16(
1716 return DdeGetData(hData, pDst, cbMax, cbOff);
1720 /*****************************************************************
1721 * DdeAccessData16 (DDEML.17)
1723 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1725 return DdeAccessData(hData, pcbDataSize);
1728 /*****************************************************************
1729 * DdeAccessData (USER32.@)
1731 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1733 FIXME("(%d,%p): stub\n", hData, pcbDataSize);
1737 /*****************************************************************
1738 * DdeUnaccessData16 (DDEML.18)
1740 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1742 return DdeUnaccessData(hData);
1745 /*****************************************************************
1746 * DdeUnaccessData (USER32.@)
1748 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1750 FIXME("(0x%x): stub\n", hData);
1755 /*****************************************************************
1756 * DdeEnableCallback16 (DDEML.26)
1758 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1760 return DdeEnableCallback(idInst, hConv, wCmd);
1763 /*****************************************************************
1764 * DdeEnableCallback (USER32.@)
1766 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1768 FIXME("(%ld, 0x%x, %d) stub\n", idInst, hConv, wCmd);
1773 /*****************************************************************
1774 * DdeNameService16 (DDEML.27)
1776 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1779 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1783 /******************************************************************************
1784 * DdeNameService [USER32.@] {Un}registers service name of DDE server
1787 * idInst [I] Instance identifier
1788 * hsz1 [I] Handle to service name string
1790 * afCmd [I] Service name flags
1796 *****************************************************************
1800 * Vn Date Author Comment
1803 * 1.1 Apr 1999 Keith Matthews Added trap for non-existent instance (uninitialised instance 0
1804 * used by some MS programs for unfathomable reasons)
1805 * 1.2 May 1999 Keith Matthews Added parameter validation and basic service name handling.
1806 * Still needs callback parts
1809 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1812 ServiceNode* this_service, *reference_service ;
1813 DDE_HANDLE_ENTRY *this_instance;
1814 DDE_HANDLE_ENTRY *reference_inst;
1815 this_service = NULL;
1817 FIXME("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1819 if ( DDE_Max_Assigned_Instance == 0 )
1821 /* Nothing has been initialised - exit now !
1822 * needs something for DdeGetLastError */
1826 if ( !WaitForMutex(handle_mutex) )
1828 return DMLERR_SYS_ERROR;
1831 TRACE("Handle Mutex created/reserved\n");
1833 /* First check instance
1835 reference_inst = Find_Instance_Entry(idInst);
1836 this_instance = reference_inst;
1837 if (reference_inst == NULL)
1839 TRACE("Instance not found as initialised\n");
1840 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return TRUE;
1841 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1848 /* Illegal, reserved parameter
1850 reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1851 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1852 FIXME("Reserved parameter no-zero !!\n");
1858 * General unregister situation
1860 if ( afCmd != DNS_UNREGISTER )
1862 /* don't know if we should check this but it makes sense
1863 * why supply REGISTER or filter flags if de-registering all
1865 TRACE("General unregister unexpected flags\n");
1866 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1867 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1870 /* Loop to find all registered service and de-register them
1872 if ( reference_inst->ServiceNames == NULL )
1874 /* None to unregister !!
1876 TRACE("General de-register - nothing registered\n");
1877 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1878 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1882 this_service = reference_inst->ServiceNames;
1883 while ( this_service->next != NULL)
1885 TRACE("general deregister - iteration\n");
1886 reference_service = this_service;
1887 this_service = this_service->next;
1888 DdeReleaseAtom(reference_inst,reference_service->hsz);
1889 HeapFree(GetProcessHeap(), 0, reference_service); /* finished - release heap space used as work store */
1891 DdeReleaseAtom(reference_inst,this_service->hsz);
1892 HeapFree(GetProcessHeap(), 0, this_service); /* finished - release heap space used as work store */
1893 reference_inst->ServiceNames = NULL;
1894 TRACE("General de-register - finished\n");
1896 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1899 TRACE("Specific name action detected\n");
1900 if ( afCmd & DNS_REGISTER )
1902 /* Register new service name
1905 this_service = Find_Service_Name( hsz1, reference_inst );
1907 ERR("Trying to register already registered service!\n");
1910 TRACE("Adding service name\n");
1912 DdeReserveAtom(reference_inst, hsz1);
1914 this_service = (ServiceNode*)HeapAlloc( GetProcessHeap(), 0, sizeof(ServiceNode) );
1915 this_service->hsz = hsz1;
1916 this_service->FilterOn = TRUE;
1918 this_service->next = reference_inst->ServiceNames;
1919 reference_inst->ServiceNames = this_service;
1922 if ( afCmd & DNS_UNREGISTER )
1924 /* De-register service name
1927 ServiceNode **pServiceNode = &reference_inst->ServiceNames;
1928 while ( *pServiceNode && (*pServiceNode)->hsz != hsz1 )
1929 pServiceNode = &(*pServiceNode)->next;
1931 this_service = *pServiceNode;
1932 if ( !this_service )
1933 ERR("Trying to de-register unregistered service!\n");
1936 *pServiceNode = this_service->next;
1937 DdeReleaseAtom(reference_inst,this_service->hsz);
1938 HeapFree(GetProcessHeap(), 0, this_service);
1941 if ( afCmd & DNS_FILTERON )
1943 /* Set filter flags on to hold notifications of connection
1945 * test coded this way as this is the default setting
1947 this_service = Find_Service_Name( hsz1, reference_inst );
1948 if ( !this_service )
1950 /* trying to filter where no service names !!
1952 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1953 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1957 this_service->FilterOn = TRUE;
1960 if ( afCmd & DNS_FILTEROFF )
1962 /* Set filter flags on to hold notifications of connection
1964 this_service = Find_Service_Name( hsz1, reference_inst );
1965 if ( !this_service )
1967 /* trying to filter where no service names !!
1969 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1970 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1974 this_service->FilterOn = FALSE;
1977 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1982 /*****************************************************************
1983 * DdeGetLastError16 (DDEML.20)
1985 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1987 return (UINT16)DdeGetLastError( idInst );
1991 /******************************************************************************
1992 * DdeGetLastError [USER32.@] Gets most recent error code
1995 * idInst [I] Instance identifier
2000 *****************************************************************
2004 * Vn Date Author Comment
2007 * 1.1 Apr 1999 Keith Matthews Added response for non-existent instance (uninitialised instance 0
2008 * used by some MS programs for unfathomable reasons)
2009 * 1.2 May 1999 Keith Matthews Added interrogation of Last_Error for instance handle where found.
2012 UINT WINAPI DdeGetLastError( DWORD idInst )
2015 DDE_HANDLE_ENTRY *reference_inst;
2017 FIXME("(%ld): stub\n",idInst);
2019 if ( DDE_Max_Assigned_Instance == 0 )
2021 /* Nothing has been initialised - exit now ! */
2022 return DMLERR_DLL_NOT_INITIALIZED;
2025 if ( !WaitForMutex(handle_mutex) )
2027 return DMLERR_SYS_ERROR;
2030 TRACE("Handle Mutex created/reserved\n");
2032 /* First check instance
2034 reference_inst = Find_Instance_Entry(idInst);
2035 if (reference_inst == NULL)
2037 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
2038 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2039 return DMLERR_DLL_NOT_INITIALIZED;
2042 error_code = reference_inst->Last_Error;
2043 reference_inst->Last_Error = 0;
2044 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
2049 /*****************************************************************
2050 * DdeCmpStringHandles16 (DDEML.36)
2052 INT16 WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2054 return DdeCmpStringHandles(hsz1, hsz2);
2057 /*****************************************************************
2058 * DdeCmpStringHandles (USER32.@)
2060 * Compares the value of two string handles. This comparison is
2061 * not case sensitive.
2064 * -1 The value of hsz1 is zero or less than hsz2
2065 * 0 The values of hsz 1 and 2 are the same or both zero.
2066 * 1 The value of hsz2 is zero of less than hsz1
2068 INT WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2070 CHAR psz1[MAX_BUFFER_LEN];
2071 CHAR psz2[MAX_BUFFER_LEN];
2075 TRACE("handle 1, handle 2\n" );
2077 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2078 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2079 /* Make sure we found both strings.
2081 if( ret1 == 0 && ret2 == 0 )
2083 /* If both are not found, return both "zero strings".
2087 else if( ret1 == 0 )
2089 /* If hsz1 is a not found, return hsz1 is "zero string".
2093 else if( ret2 == 0 )
2095 /* If hsz2 is a not found, return hsz2 is "zero string".
2101 /* Compare the two strings we got ( case insensitive ).
2103 ret = strcasecmp( psz1, psz2 );
2104 /* Since strcmp returns any number smaller than
2105 * 0 when the first string is found to be less than
2106 * the second one we must make sure we are returning
2107 * the proper values.
2122 /*****************************************************************
2123 * PackDDElParam (USER32.@)
2128 LPARAM WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2135 /*****************************************************************
2136 * UnpackDDElParam (USER32.@)
2142 BOOL WINAPI UnpackDDElParam(UINT msg, LPARAM lParam,
2143 PUINT uiLo, PUINT uiHi)
2150 /*****************************************************************
2151 * FreeDDElParam (USER32.@)
2157 BOOL WINAPI FreeDDElParam(UINT msg, LPARAM lParam)
2163 /*****************************************************************
2164 * ReuseDDElParam (USER32.@)
2169 LPARAM WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2170 UINT uiLi, UINT uiHi)
2176 /******************************************************************
2177 * DdeQueryConvInfo16 (DDEML.9)
2180 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2187 /******************************************************************
2188 * DdeQueryConvInfo (USER32.@)
2191 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)