4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Len White
6 * Copyright 1999 Keith Matthews
9 /* Only empty stubs for now */
20 #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,1,DDEInstanceAccess); /* 1st time through */
383 inst_count_mutex = ConvertToGlobalHandle(inst_count_mutex); /* fixme when having seperate adresspaces*/
385 if ( !WaitForMutex(inst_count_mutex) )
387 return DMLERR_SYS_ERROR;
390 if ( !inst_count_mutex )
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.106)
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.107]
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,1,DDEHandleAccess);
616 handle_mutex = ConvertToGlobalHandle(handle_mutex); /* fixme when having seperate adresspaces*/
617 if ( !handle_mutex ) {
618 ERR("CreateMutex failed - handle list %li\n",GetLastError());
619 HeapFree(GetProcessHeap(), 0, this_instance);
620 return DMLERR_SYS_ERROR;
623 if ( !WaitForMutex(handle_mutex) )
625 return DMLERR_SYS_ERROR;
629 TRACE("Handle Mutex created/reserved\n");
630 if (DDE_Handle_Table_Base == NULL )
632 /* can't be another instance in this case, assign to the base pointer */
633 DDE_Handle_Table_Base= this_instance;
635 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
637 * ------------------------------- NOTE NOTE NOTE --------------------------
639 * the manual is not clear if this condition
640 * applies to the first call to DdeInitialize from an application, or the
641 * first call for a given callback !!!
644 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
645 TRACE("First application instance detected OK\n");
646 /* allocate new instance ID */
647 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
650 /* really need to chain the new one in to the latest here, but after checking conditions
651 * such as trying to start a conversation from an application trying to monitor */
652 reference_inst = DDE_Handle_Table_Base;
653 TRACE("Subsequent application instance - starting checks\n");
654 while ( reference_inst->Next_Entry != NULL )
657 * This set of tests will work if application uses same instance Id
658 * at application level once allocated - which is what manual implies
659 * should happen. If someone tries to be
660 * clever (lazy ?) it will fail to pick up that later calls are for
661 * the same application - should we trust them ?
663 if ( this_instance->Instance_id == reference_inst->Instance_id)
665 /* Check 1 - must be same Client-only state */
667 if ( this_instance->Client_only != reference_inst->Client_only)
669 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
670 return DMLERR_SYS_ERROR;
671 return DMLERR_DLL_USAGE;
674 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
676 if ( this_instance->Monitor != reference_inst->Monitor)
678 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
679 return DMLERR_SYS_ERROR;
680 return DMLERR_INVALIDPARAMETER;
683 /* Check 3 - must supply different callback address */
685 if ( this_instance->CallBack == reference_inst->CallBack)
687 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
688 return DMLERR_SYS_ERROR;
689 return DMLERR_DLL_USAGE;
692 reference_inst = reference_inst->Next_Entry;
694 /* All cleared, add to chain */
696 TRACE("Application Instance checks finished\n");
697 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
698 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0,this_instance)) return DMLERR_SYS_ERROR;
699 reference_inst->Next_Entry = this_instance;
701 *pidInst = this_instance->Instance_id;
702 TRACE("New application instance processing finished OK\n");
704 /* Reinitialisation situation --- FIX */
705 TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
707 if ( !WaitForMutex(handle_mutex) )
709 HeapFree(GetProcessHeap(), 0, this_instance);
710 return DMLERR_SYS_ERROR;
713 if (DDE_Handle_Table_Base == NULL )
715 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance)) return DMLERR_SYS_ERROR;
716 return DMLERR_DLL_USAGE;
718 HeapFree(GetProcessHeap(), 0, this_instance); /* finished - release heap space used as work store */
719 /* can't reinitialise if we have initialised nothing !! */
720 reference_inst = DDE_Handle_Table_Base;
721 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
723 * MS allows initialisation without specifying a callback, should we allow addition of the
724 * callback by a later call to initialise ? - if so this lot will have to change
726 while ( reference_inst->Next_Entry != NULL )
728 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
730 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
732 if ( reference_inst->Client_only )
734 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
736 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
738 if ( ! ( afCmd & APPCMD_CLIENTONLY))
740 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
741 return DMLERR_SYS_ERROR;
742 return DMLERR_DLL_USAGE;
746 /* Check 2 - cannot change monitor modes */
748 if ( this_instance->Monitor != reference_inst->Monitor)
750 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
751 return DMLERR_SYS_ERROR;
752 return DMLERR_DLL_USAGE;
755 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
757 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
759 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
760 return DMLERR_SYS_ERROR;
761 return DMLERR_DLL_USAGE;
765 reference_inst = reference_inst->Next_Entry;
767 if ( reference_inst->Next_Entry == NULL )
769 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
771 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
773 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
774 return DMLERR_SYS_ERROR;
775 return DMLERR_INVALIDPARAMETER;
777 /* All checked - change relevant flags */
779 reference_inst->CBF_Flags = this_instance->CBF_Flags;
780 reference_inst->Client_only = this_instance->Client_only;
781 reference_inst->Monitor_flags = this_instance->Monitor_flags;
782 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
783 return DMLERR_SYS_ERROR;
786 return DMLERR_NO_ERROR;
790 /*****************************************************************
791 * DdeUninitialize16 (DDEML.3)
793 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
795 FIXME(" stub calling DdeUninitialize\n");
796 return (BOOL16)DdeUninitialize( idInst );
800 /*****************************************************************
801 * DdeUninitialize [USER32.119] Frees DDEML resources
804 * idInst [I] Instance identifier
811 BOOL WINAPI DdeUninitialize( DWORD idInst )
813 /* Stage one - check if we have a handle for this instance
815 SECURITY_ATTRIBUTES *s_att= NULL;
816 SECURITY_ATTRIBUTES s_attrib;
817 DDE_HANDLE_ENTRY *this_instance;
818 DDE_HANDLE_ENTRY *reference_inst;
821 if ( DDE_Max_Assigned_Instance == 0 )
823 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
827 if ( !WaitForMutex(handle_mutex) )
829 return DMLERR_SYS_ERROR;
831 TRACE("Handle Mutex created/reserved\n");
832 /* First check instance
834 this_instance = Find_Instance_Entry(idInst);
835 if ( this_instance == NULL )
837 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return FALSE;
839 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
843 FIXME("(%ld): partial stub\n", idInst);
845 /* FIXME ++++++++++++++++++++++++++++++++++++++++++
846 * Needs to de-register all service names
849 /* Free the nodes that were not freed by this instance
850 * and remove the nodes from the list of HSZ nodes.
852 FreeAndRemoveHSZNodes( idInst, this_instance );
854 /* OK now delete the instance handle itself */
856 if ( DDE_Handle_Table_Base == this_instance )
858 /* special case - the first/only entry
860 DDE_Handle_Table_Base = this_instance->Next_Entry;
865 reference_inst = DDE_Handle_Table_Base;
866 while ( reference_inst->Next_Entry != this_instance )
868 reference_inst = this_instance->Next_Entry;
870 reference_inst->Next_Entry = this_instance->Next_Entry;
872 /* release the mutex and the heap entry
874 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE,this_instance))
876 /* should record something here, but nothing left to hang it from !!
884 /*****************************************************************
885 * DdeConnectList16 [DDEML.4]
888 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
889 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
891 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
896 /******************************************************************************
897 * DdeConnectList [USER32.93] Establishes conversation with DDE servers
900 * idInst [I] Instance identifier
901 * hszService [I] Handle to service name string
902 * hszTopic [I] Handle to topic name string
903 * hConvList [I] Handle to conversation list
904 * pCC [I] Pointer to structure with context data
907 * Success: Handle to new conversation list
910 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
911 HCONVLIST hConvList, LPCONVCONTEXT pCC )
913 FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
919 /*****************************************************************
920 * DdeQueryNextServer16 [DDEML.5]
922 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
924 return DdeQueryNextServer(hConvList, hConvPrev);
928 /*****************************************************************
929 * DdeQueryNextServer [USER32.112]
931 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
933 FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
937 /*****************************************************************
938 * DdeQueryStringA [USER32.113]
940 *****************************************************************
944 * Vn Date Author Comment
946 * 1.0 Dec 1998 Corel/Macadamian Initial version
947 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
950 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
953 CHAR pString[MAX_BUFFER_LEN];
954 DDE_HANDLE_ENTRY *reference_inst;
957 "(%ld, 0x%x, %p, %ld, %d): partial stub\n",
963 if ( DDE_Max_Assigned_Instance == 0 )
965 /* Nothing has been initialised - exit now ! */
966 /* needs something for DdeGetLAstError even if the manual doesn't say so */
970 if ( !WaitForMutex(handle_mutex) )
975 TRACE("Handle Mutex created/reserved\n");
977 /* First check instance
979 reference_inst = Find_Instance_Entry(idInst);
980 if ( reference_inst == NULL )
982 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
984 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
989 if( iCodePage == CP_WINANSI )
991 /* If psz is null, we have to return only the length
997 cchMax = MAX_BUFFER_LEN;
1000 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
1002 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1004 TRACE("returning pointer\n");
1008 /*****************************************************************
1009 * DdeQueryStringW [USER32.114]
1011 *****************************************************************
1015 * Vn Date Author Comment
1017 * 1.0 Dec 1998 Corel/Macadamian Initial version
1021 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1024 WCHAR pString[MAX_BUFFER_LEN];
1028 "(%ld, 0x%x, %p, %ld, %d): stub\n",
1035 if( iCodePage == CP_WINUNICODE )
1037 /* If psz is null, we have to return only the length
1043 cchMax = MAX_BUFFER_LEN;
1044 /* Note: According to documentation if the psz parameter
1045 * was NULL this API must return the length of the string in bytes.
1047 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1049 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1054 /*****************************************************************
1056 * DdeQueryString16 (DDEML.23)
1058 ******************************************************************
1062 * Vn Date Author Comment
1064 * 1.0 March 1999 K Matthews stub only
1067 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, INT16 codepage)
1069 FIXME("(%ld, 0x%x, %p, %ld, %d): stub \n",
1079 /*****************************************************************
1080 * DdeDisconnectList (DDEML.6)
1082 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1084 return (BOOL16)DdeDisconnectList(hConvList);
1088 /******************************************************************************
1089 * DdeDisconnectList [USER32.98] Destroys list and terminates conversations
1095 BOOL WINAPI DdeDisconnectList(
1096 HCONVLIST hConvList) /* [in] Handle to conversation list */
1098 FIXME("(%d): stub\n", hConvList);
1103 /*****************************************************************
1104 * DdeConnect16 (DDEML.7)
1106 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1107 LPCONVCONTEXT16 pCC )
1109 FIXME("empty stub\n" );
1114 /*****************************************************************
1115 * DdeConnect (USER32.92)
1117 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1120 FIXME("(0x%lx,%d,%d,%p): stub\n",idInst,hszService,hszTopic,
1126 /*****************************************************************
1127 * DdeDisconnect16 (DDEML.8)
1129 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1131 return (BOOL16)DdeDisconnect( hConv );
1134 /*****************************************************************
1135 * DdeSetUserHandle16 (DDEML.10)
1137 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1139 FIXME("(%d,%ld,%ld): stub\n",hConv,id, hUser );
1143 /*****************************************************************
1144 * DdeCreateDataHandle16 (DDEML.14)
1146 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
1147 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
1150 return DdeCreateDataHandle(idInst,
1159 /*****************************************************************
1160 * DdeCreateDataHandle (USER32.94)
1162 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
1163 DWORD cbOff, HSZ hszItem, UINT wFmt,
1167 "(%ld,%p,%ld,%ld,0x%x,%d,%d): stub\n",
1179 /*****************************************************************
1180 * DdeDisconnect (USER32.97)
1182 BOOL WINAPI DdeDisconnect( HCONV hConv )
1184 FIXME("empty stub\n" );
1189 /*****************************************************************
1190 * DdeReconnect (DDEML.37) (USER32.115)
1192 HCONV WINAPI DdeReconnect( HCONV hConv )
1194 FIXME("empty stub\n" );
1199 /*****************************************************************
1200 * DdeCreateStringHandle16 (DDEML.21)
1202 *****************************************************************
1206 * Vn Date Author Comment
1208 * 1.0 ? ? basic stub
1209 * 1.1 June 1999 Keith Matthews amended onward call to supply default
1210 * code page if none supplied by caller
1212 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1216 return DdeCreateStringHandleA( idInst, str, codepage );
1218 TRACE("Default codepage supplied\n");
1219 return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1224 /*****************************************************************
1225 * DdeCreateStringHandleA [USER32.95]
1228 * Success: String handle
1231 *****************************************************************
1235 * Vn Date Author Comment
1237 * 1.0 Dec 1998 Corel/Macadamian Initial version
1238 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1241 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1244 DDE_HANDLE_ENTRY *reference_inst;
1245 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1248 if ( DDE_Max_Assigned_Instance == 0 )
1250 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1254 if ( !WaitForMutex(handle_mutex) )
1256 return DMLERR_SYS_ERROR;
1259 TRACE("Handle Mutex created/reserved\n");
1261 /* First check instance
1263 reference_inst = Find_Instance_Entry(idInst);
1264 if ( reference_inst == NULL )
1266 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1268 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1273 if (codepage==CP_WINANSI)
1275 hsz = GlobalAddAtomA (psz);
1276 /* Save the handle so we know to clean it when
1277 * uninitialize is called.
1279 TRACE("added atom %s with HSZ 0x%x, \n",debugstr_a(psz),hsz);
1280 InsertHSZNode( hsz, reference_inst );
1281 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1283 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1286 TRACE("Returning pointer\n");
1289 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1291 TRACE("Returning error\n");
1296 /******************************************************************************
1297 * DdeCreateStringHandleW [USER32.96] Creates handle to identify string
1300 * Success: String handle
1303 *****************************************************************
1307 * Vn Date Author Comment
1309 * 1.0 Dec 1998 Corel/Macadamian Initial version
1310 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1313 HSZ WINAPI DdeCreateStringHandleW(
1314 DWORD idInst, /* [in] Instance identifier */
1315 LPCWSTR psz, /* [in] Pointer to string */
1316 INT codepage) /* [in] Code page identifier */
1318 DDE_HANDLE_ENTRY *reference_inst;
1321 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1324 if ( DDE_Max_Assigned_Instance == 0 )
1326 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1330 if ( !WaitForMutex(handle_mutex) )
1332 return DMLERR_SYS_ERROR;
1335 TRACE("CreateString - Handle Mutex created/reserved\n");
1337 /* First check instance
1339 reference_inst = Find_Instance_Entry(idInst);
1340 if ( reference_inst == NULL )
1342 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1344 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1349 FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1351 if (codepage==CP_WINUNICODE)
1353 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1356 hsz = GlobalAddAtomW (psz);
1357 /* Save the handle so we know to clean it when
1358 * uninitialize is called.
1360 InsertHSZNode( hsz, reference_inst );
1361 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1363 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1366 TRACE("Returning pointer\n");
1369 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1371 TRACE("Returning error\n");
1376 /*****************************************************************
1377 * DdeFreeStringHandle16 (DDEML.22)
1379 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1381 FIXME("idInst %ld hsz 0x%x\n",idInst,hsz);
1382 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1386 /*****************************************************************
1387 * DdeFreeStringHandle (USER32.101)
1388 * RETURNS: success: nonzero
1391 *****************************************************************
1395 * Vn Date Author Comment
1397 * 1.0 Dec 1998 Corel/Macadamian Initial version
1398 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1401 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1403 DDE_HANDLE_ENTRY *reference_inst;
1404 TRACE("(%ld,%d): \n",idInst,hsz);
1405 if ( DDE_Max_Assigned_Instance == 0 )
1407 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1411 if ( !WaitForMutex(handle_mutex) )
1413 return DMLERR_SYS_ERROR;
1416 TRACE("Handle Mutex created/reserved\n");
1418 /* First check instance
1420 reference_inst = Find_Instance_Entry(idInst);
1421 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1423 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
1424 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1429 /* Remove the node associated with this HSZ.
1431 RemoveHSZNode( hsz , reference_inst);
1432 /* Free the string associated with this HSZ.
1434 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1435 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1439 /*****************************************************************
1440 * DdeFreeDataHandle16 (DDEML.19)
1442 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1444 return (BOOL)DdeFreeDataHandle( hData );
1448 /*****************************************************************
1449 * DdeFreeDataHandle (USER32.100)
1451 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1453 FIXME("empty stub\n" );
1460 /*****************************************************************
1461 * DdeKeepStringHandle16 (DDEML.24)
1463 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1465 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1469 /*****************************************************************
1470 * DdeKeepStringHandle (USER32.108)
1472 * RETURNS: success: nonzero
1475 *****************************************************************
1479 * Vn Date Author Comment
1482 * 1.1 Jun 1999 Keith Matthews First cut implementation
1485 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1488 DDE_HANDLE_ENTRY *reference_inst;
1489 TRACE("(%ld,%d): \n",idInst,hsz);
1490 if ( DDE_Max_Assigned_Instance == 0 )
1492 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1497 if ( !WaitForMutex(handle_mutex) )
1502 TRACE("Handle Mutex created/reserved\n");
1504 /* First check instance
1506 reference_inst = Find_Instance_Entry(idInst);
1507 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1509 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
1510 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1514 DdeReserveAtom(reference_inst,hsz);
1515 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1520 /*****************************************************************
1521 * DdeClientTransaction16 (DDEML.11)
1523 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1524 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1525 UINT16 wType, DWORD dwTimeout,
1528 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1529 wFmt, wType, dwTimeout, pdwResult );
1533 /*****************************************************************
1534 * DdeClientTransaction (USER32.90)
1536 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1537 HCONV hConv, HSZ hszItem, UINT wFmt,
1538 UINT wType, DWORD dwTimeout,
1541 FIXME("empty stub\n" );
1545 /*****************************************************************
1547 * DdeAbandonTransaction16 (DDEML.12)
1550 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1551 DWORD idTransaction )
1553 FIXME("empty stub\n" );
1558 /*****************************************************************
1560 * DdeAbandonTransaction (USER32.87)
1562 ******************************************************************
1566 * Vn Date Author Comment
1568 * 1.0 March 1999 K Matthews stub only
1570 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1571 DWORD idTransaction )
1573 FIXME("empty stub\n" );
1577 /*****************************************************************
1578 * DdePostAdvise16 [DDEML.13]
1580 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1582 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1586 /******************************************************************************
1587 * DdePostAdvise [USER32.110] Send transaction to DDE callback function.
1593 BOOL WINAPI DdePostAdvise(
1594 DWORD idInst, /* [in] Instance identifier */
1595 HSZ hszTopic, /* [in] Handle to topic name string */
1596 HSZ hszItem) /* [in] Handle to item name string */
1598 FIXME("(%ld,%d,%d): stub\n",idInst,hszTopic,hszItem);
1603 /*****************************************************************
1604 * DdeAddData16 (DDEML.15)
1606 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1609 FIXME("empty stub\n" );
1613 /*****************************************************************
1615 * DdeAddData (USER32.89)
1617 ******************************************************************
1621 * Vn Date Author Comment
1623 * 1.0 March 1999 K Matthews stub only
1625 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1628 FIXME("empty stub\n" );
1633 /*****************************************************************
1635 * DdeImpersonateClient (USER32.105)
1637 ******************************************************************
1641 * Vn Date Author Comment
1643 * 1.0 March 1999 K Matthews stub only
1646 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1648 FIXME("empty stub\n" );
1653 /*****************************************************************
1655 * DdeSetQualityOfService (USER32.116)
1657 ******************************************************************
1661 * Vn Date Author Comment
1663 * 1.0 March 1999 K Matthews stub only
1666 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1667 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1669 FIXME("empty stub\n" );
1673 /*****************************************************************
1675 * DdeSetUserHandle (USER32.117)
1677 ******************************************************************
1681 * Vn Date Author Comment
1683 * 1.0 March 1999 K Matthews stub only
1686 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1688 FIXME("empty stub\n" );
1692 /******************************************************************************
1693 * DdeGetData [USER32.102] Copies data from DDE object ot local buffer
1696 * Size of memory object associated with handle
1698 DWORD WINAPI DdeGetData(
1699 HDDEDATA hData, /* [in] Handle to DDE object */
1700 LPBYTE pDst, /* [in] Pointer to destination buffer */
1701 DWORD cbMax, /* [in] Amount of data to copy */
1702 DWORD cbOff) /* [in] Offset to beginning of data */
1704 FIXME("(%d,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1709 /*****************************************************************
1710 * DdeGetData16 [DDEML.16]
1712 DWORD WINAPI DdeGetData16(
1718 return DdeGetData(hData, pDst, cbMax, cbOff);
1722 /*****************************************************************
1723 * DdeAccessData16 (DDEML.17)
1725 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1727 return DdeAccessData(hData, pcbDataSize);
1730 /*****************************************************************
1731 * DdeAccessData (USER32.88)
1733 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1735 FIXME("(%d,%p): stub\n", hData, pcbDataSize);
1739 /*****************************************************************
1740 * DdeUnaccessData16 (DDEML.18)
1742 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1744 return DdeUnaccessData(hData);
1747 /*****************************************************************
1748 * DdeUnaccessData (USER32.118)
1750 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1752 FIXME("(0x%x): stub\n", hData);
1757 /*****************************************************************
1758 * DdeEnableCallback16 (DDEML.26)
1760 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1762 return DdeEnableCallback(idInst, hConv, wCmd);
1765 /*****************************************************************
1766 * DdeEnableCallback (USER32.99)
1768 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1770 FIXME("(%ld, 0x%x, %d) stub\n", idInst, hConv, wCmd);
1775 /*****************************************************************
1776 * DdeNameService16 (DDEML.27)
1778 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1781 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1785 /******************************************************************************
1786 * DdeNameService [USER32.109] {Un}registers service name of DDE server
1789 * idInst [I] Instance identifier
1790 * hsz1 [I] Handle to service name string
1792 * afCmd [I] Service name flags
1798 *****************************************************************
1802 * Vn Date Author Comment
1805 * 1.1 Apr 1999 Keith Matthews Added trap for non-existent instance (uninitialised instance 0
1806 * used by some MS programs for unfathomable reasons)
1807 * 1.2 May 1999 Keith Matthews Added parameter validation and basic service name handling.
1808 * Still needs callback parts
1811 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1814 ServiceNode* this_service, *reference_service ;
1815 DDE_HANDLE_ENTRY *this_instance;
1816 DDE_HANDLE_ENTRY *reference_inst;
1817 this_service = NULL;
1819 FIXME("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1821 if ( DDE_Max_Assigned_Instance == 0 )
1823 /* Nothing has been initialised - exit now !
1824 * needs something for DdeGetLastError */
1828 if ( !WaitForMutex(handle_mutex) )
1830 return DMLERR_SYS_ERROR;
1833 TRACE("Handle Mutex created/reserved\n");
1835 /* First check instance
1837 reference_inst = Find_Instance_Entry(idInst);
1838 this_instance = reference_inst;
1839 if (reference_inst == NULL)
1841 TRACE("Instance not found as initialised\n");
1842 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return TRUE;
1843 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1850 /* Illegal, reserved parameter
1852 reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1853 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1854 FIXME("Reserved parameter no-zero !!\n");
1860 * General unregister situation
1862 if ( afCmd != DNS_UNREGISTER )
1864 /* don't know if we should check this but it makes sense
1865 * why supply REGISTER or filter flags if de-registering all
1867 TRACE("General unregister unexpected flags\n");
1868 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1869 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1872 /* Loop to find all registered service and de-register them
1874 if ( reference_inst->ServiceNames == NULL )
1876 /* None to unregister !!
1878 TRACE("General de-register - nothing registered\n");
1879 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1880 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1884 this_service = reference_inst->ServiceNames;
1885 while ( this_service->next != NULL)
1887 TRACE("general deregister - iteration\n");
1888 reference_service = this_service;
1889 this_service = this_service->next;
1890 DdeReleaseAtom(reference_inst,reference_service->hsz);
1891 HeapFree(GetProcessHeap(), 0, reference_service); /* finished - release heap space used as work store */
1893 DdeReleaseAtom(reference_inst,this_service->hsz);
1894 HeapFree(GetProcessHeap(), 0, this_service); /* finished - release heap space used as work store */
1895 reference_inst->ServiceNames = NULL;
1896 TRACE("General de-register - finished\n");
1898 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1901 TRACE("Specific name action detected\n");
1902 if ( afCmd & DNS_REGISTER )
1904 /* Register new service name
1907 this_service = Find_Service_Name( hsz1, reference_inst );
1909 ERR("Trying to register already registered service!\n");
1912 TRACE("Adding service name\n");
1914 DdeReserveAtom(reference_inst, hsz1);
1916 this_service = (ServiceNode*)HeapAlloc( GetProcessHeap(), 0, sizeof(ServiceNode) );
1917 this_service->hsz = hsz1;
1918 this_service->FilterOn = TRUE;
1920 this_service->next = reference_inst->ServiceNames;
1921 reference_inst->ServiceNames = this_service;
1924 if ( afCmd & DNS_UNREGISTER )
1926 /* De-register service name
1929 ServiceNode **pServiceNode = &reference_inst->ServiceNames;
1930 while ( *pServiceNode && (*pServiceNode)->hsz != hsz1 )
1931 pServiceNode = &(*pServiceNode)->next;
1933 this_service = *pServiceNode;
1934 if ( !this_service )
1935 ERR("Trying to de-register unregistered service!\n");
1938 *pServiceNode = this_service->next;
1939 DdeReleaseAtom(reference_inst,this_service->hsz);
1940 HeapFree(GetProcessHeap(), 0, this_service);
1943 if ( afCmd & DNS_FILTERON )
1945 /* Set filter flags on to hold notifications of connection
1947 * test coded this way as this is the default setting
1949 this_service = Find_Service_Name( hsz1, reference_inst );
1950 if ( !this_service )
1952 /* trying to filter where no service names !!
1954 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1955 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1959 this_service->FilterOn = TRUE;
1962 if ( afCmd & DNS_FILTEROFF )
1964 /* Set filter flags on to hold notifications of connection
1966 this_service = Find_Service_Name( hsz1, reference_inst );
1967 if ( !this_service )
1969 /* trying to filter where no service names !!
1971 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1972 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1976 this_service->FilterOn = FALSE;
1979 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1984 /*****************************************************************
1985 * DdeGetLastError16 (DDEML.20)
1987 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1989 return (UINT16)DdeGetLastError( idInst );
1993 /******************************************************************************
1994 * DdeGetLastError [USER32.103] Gets most recent error code
1997 * idInst [I] Instance identifier
2002 *****************************************************************
2006 * Vn Date Author Comment
2009 * 1.1 Apr 1999 Keith Matthews Added response for non-existent instance (uninitialised instance 0
2010 * used by some MS programs for unfathomable reasons)
2011 * 1.2 May 1999 Keith Matthews Added interrogation of Last_Error for instance handle where found.
2014 UINT WINAPI DdeGetLastError( DWORD idInst )
2017 DDE_HANDLE_ENTRY *reference_inst;
2019 FIXME("(%ld): stub\n",idInst);
2021 if ( DDE_Max_Assigned_Instance == 0 )
2023 /* Nothing has been initialised - exit now ! */
2024 return DMLERR_DLL_NOT_INITIALIZED;
2027 if ( !WaitForMutex(handle_mutex) )
2029 return DMLERR_SYS_ERROR;
2032 TRACE("Handle Mutex created/reserved\n");
2034 /* First check instance
2036 reference_inst = Find_Instance_Entry(idInst);
2037 if (reference_inst == NULL)
2039 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
2040 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2041 return DMLERR_DLL_NOT_INITIALIZED;
2044 error_code = reference_inst->Last_Error;
2045 reference_inst->Last_Error = 0;
2046 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
2051 /*****************************************************************
2052 * DdeCmpStringHandles16 (DDEML.36)
2054 INT16 WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2056 return DdeCmpStringHandles(hsz1, hsz2);
2059 /*****************************************************************
2060 * DdeCmpStringHandles (USER32.91)
2062 * Compares the value of two string handles. This comparison is
2063 * not case sensitive.
2066 * -1 The value of hsz1 is zero or less than hsz2
2067 * 0 The values of hsz 1 and 2 are the same or both zero.
2068 * 1 The value of hsz2 is zero of less than hsz1
2070 INT WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2072 CHAR psz1[MAX_BUFFER_LEN];
2073 CHAR psz2[MAX_BUFFER_LEN];
2077 TRACE("handle 1, handle 2\n" );
2079 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2080 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2081 /* Make sure we found both strings.
2083 if( ret1 == 0 && ret2 == 0 )
2085 /* If both are not found, return both "zero strings".
2089 else if( ret1 == 0 )
2091 /* If hsz1 is a not found, return hsz1 is "zero string".
2095 else if( ret2 == 0 )
2097 /* If hsz2 is a not found, return hsz2 is "zero string".
2103 /* Compare the two strings we got ( case insensitive ).
2105 ret = strcasecmp( psz1, psz2 );
2106 /* Since strcmp returns any number smaller than
2107 * 0 when the first string is found to be less than
2108 * the second one we must make sure we are returning
2109 * the proper values.
2124 /*****************************************************************
2125 * PackDDElParam (USER32.414)
2131 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2138 /*****************************************************************
2139 * UnpackDDElParam (USER32.562)
2145 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
2146 UINT *uiLo, UINT *uiHi)
2153 /*****************************************************************
2154 * FreeDDElParam (USER32.204)
2160 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
2166 /*****************************************************************
2167 * ReuseDDElParam (USER32.446)
2170 UINT WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2171 UINT uiLi, UINT uiHi)
2177 /******************************************************************
2178 * DdeQueryConvInfo16 (DDEML.9)
2181 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2188 /******************************************************************
2189 * DdeQueryConvInfo (USER32.111)
2192 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)