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"
23 DEFAULT_DEBUG_CHANNEL(ddeml);
25 /* Has defined in atom.c file.
27 #define MAX_ATOM_LEN 255
29 /* Maximum buffer size ( including the '\0' ).
31 #define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1)
35 LPVOID lpSecurityDescriptor;
37 } SECURITY_ATTRIBUTES; */
39 /* This is a simple list to keep track of the strings created
40 * by DdeCreateStringHandle. The list is used to free
41 * the strings whenever DdeUninitialize is called.
42 * This mechanism is not complete and does not handle multiple instances.
43 * Most of the DDE API use a DWORD parameter indicating which instance
44 * of a given program is calling them. The API are supposed to
45 * associate the data to the instance that created it.
47 typedef struct tagHSZNode HSZNode;
55 typedef struct tagServiceNode ServiceNode;
62 typedef struct DDE_HANDLE_ENTRY {
63 BOOL16 Monitor; /* have these two as full Booleans cos they'll be tested frequently */
64 BOOL16 Client_only; /* bit wasteful of space but it will be faster */
65 BOOL16 Unicode; /* Flag to indicate Win32 API used to initialise */
66 BOOL16 Win16; /* flag to indicate Win16 API used to initialize */
67 DWORD Instance_id; /* needed to track monitor usage */
68 struct DDE_HANDLE_ENTRY *Next_Entry;
73 UINT Txn_count; /* count transactions open to simplify closure */
75 ServiceNode* ServiceNames;
78 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
79 static DWORD DDE_Max_Assigned_Instance = 0; /* OK for present, may have to worry about wrap-around later */
80 static const char *DDEInstanceAccess = "DDEMaxInstance";
81 static const char *DDEHandleAccess = "DDEHandleAccess";
82 static HANDLE inst_count_mutex = 0;
83 static HANDLE handle_mutex = 0;
89 /******************************************************************************
90 * RemoveHSZNodes (INTERNAL)
92 * Remove a node from the list of HSZ nodes.
94 ******************************************************************************
98 * Vn Date Author Comment
100 * 1.0 Dec 1998 Corel/Macadamian Initial version
101 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
104 static void RemoveHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
106 HSZNode* pPrev = NULL;
107 HSZNode* pCurrent = NULL;
109 /* Set the current node at the start of the list.
111 pCurrent = reference_inst->Node_list;
112 /* While we have more nodes.
114 while( pCurrent != NULL )
116 /* If we found the node we were looking for.
118 if( pCurrent->hsz == hsz )
122 /* If the first node in the list is to to be removed.
123 * Set the global list pointer to the next node.
125 if( pCurrent == reference_inst->Node_list )
127 reference_inst->Node_list = pCurrent->next;
129 /* Just fix the pointers has to skip the current
130 * node so we can delete it.
134 pPrev->next = pCurrent->next;
136 /* Destroy this node.
141 /* Save the previous node pointer.
144 /* Move on to the next node.
146 pCurrent = pCurrent->next;
150 /******************************************************************************
151 * FreeAndRemoveHSZNodes (INTERNAL)
153 * Frees up all the strings still allocated in the list and
154 * remove all the nodes from the list of HSZ nodes.
156 ******************************************************************************
160 * Vn Date Author Comment
162 * 1.0 Dec 1998 Corel/Macadamian Initial version
163 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
166 static void FreeAndRemoveHSZNodes( DWORD idInst, DDE_HANDLE_ENTRY * reference_inst )
168 /* Free any strings created in this instance.
170 while( reference_inst->Node_list != NULL )
172 DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
176 /******************************************************************************
177 * InsertHSZNode (INTERNAL)
179 * Insert a node to the head of the list.
181 ******************************************************************************
185 * Vn Date Author Comment
187 * 1.0 Dec 1998 Corel/Macadamian Initial version
188 * 1.1 Mar 1999 Keith Matthews Added instance handling
189 * 1.2 Jun 1999 Keith Matthews Added Usage count handling
192 static void InsertHSZNode( HSZ hsz, DDE_HANDLE_ENTRY * reference_inst )
196 HSZNode* pNew = NULL;
197 /* Create a new node for this HSZ.
199 pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
202 /* Set the handle value.
205 /* Attach the node to the head of the list. i.e most recently added is first
207 pNew->next = reference_inst->Node_list;
209 /* The new node is now at the head of the list
210 * so set the global list pointer to it.
212 reference_inst->Node_list = pNew;
213 TRACE("HSZ node list entry added\n");
218 /*****************************************************************************
219 * Find_Instance_Entry
221 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
222 * for an instance Id, or NULL if the entry does not exist
224 * ASSUMES the mutex protecting the handle entry list is reserved before calling
226 ******************************************************************************
230 * Vn Date Author Comment
232 * 1.0 March 1999 Keith Matthews 1st implementation
234 DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
236 DDE_HANDLE_ENTRY * reference_inst;
237 reference_inst = DDE_Handle_Table_Base;
238 while ( reference_inst != NULL )
240 if ( reference_inst->Instance_id == InstId )
242 TRACE("Instance entry found\n");
243 return reference_inst;
245 reference_inst = reference_inst->Next_Entry;
247 TRACE("Instance entry missing\n");
251 /*****************************************************************************
254 * generic routine to return a pointer to the relevant ServiceNode
255 * for a given service name, or NULL if the entry does not exist
257 * ASSUMES the mutex protecting the handle entry list is reserved before calling
259 ******************************************************************************
263 * Vn Date Author Comment
265 * 1.0 May 1999 Keith Matthews 1st implementation
267 ServiceNode *Find_Service_Name (HSZ Service_Name, DDE_HANDLE_ENTRY* this_instance)
269 ServiceNode * reference_name= this_instance->ServiceNames;
270 while ( reference_name != NULL )
272 if ( reference_name->hsz == Service_Name )
274 TRACE("Service Name found\n");
275 return reference_name;
277 reference_name = reference_name->next;
279 TRACE("Service name missing\n");
284 /******************************************************************************
285 * Release_reserved_mutex
287 * generic routine to release a reserved mutex
290 ******************************************************************************
294 * Vn Date Author Comment
296 * 1.0 Jan 1999 Keith Matthews Initial version
297 * 1.1 Mar 1999 Keith Matthews Corrected Heap handling. Corrected re-initialisation handling
298 * 1.2 Aug 1999 Jürgen Schmied Corrected error handling
301 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i ,
302 DDE_HANDLE_ENTRY *this_instance)
304 if (!ReleaseMutex(mutex))
306 ERR("ReleaseMutex failed - %s mutex %li\n",mutex_name,GetLastError());
307 HeapFree(GetProcessHeap(), 0, this_instance);
308 if ( release_handle_m )
310 ReleaseMutex(handle_mutex);
312 return DMLERR_SYS_ERROR;
314 if ( release_this_i )
316 HeapFree(GetProcessHeap(), 0, this_instance);
318 return DMLERR_NO_ERROR;
321 /******************************************************************************
324 * generic routine to wait for the mutex
327 ******************************************************************************
331 * Vn Date Author Comment
333 * 1.0 Aug 1999 Juergen Schmied Initial version
336 static BOOL WaitForMutex (HANDLE mutex)
340 result = WaitForSingleObject(mutex,1000);
342 /* both errors should never occur */
343 if (WAIT_TIMEOUT == result)
345 ERR("WaitForSingleObject timed out\n");
349 if (WAIT_FAILED == result)
351 ERR("WaitForSingleObject failed - error %li\n", GetLastError());
356 /******************************************************************************
357 * IncrementInstanceId
359 * generic routine to increment the max instance Id and allocate a new application instance
361 ******************************************************************************
365 * Vn Date Author Comment
367 * 1.0 Jan 1999 Keith Matthews Initial version
370 DWORD IncrementInstanceId( DDE_HANDLE_ENTRY *this_instance)
372 SECURITY_ATTRIBUTES s_attrib;
374 /* Need to set up Mutex in case it is not already present */
375 /* increment handle count & get value */
376 if ( !inst_count_mutex )
378 s_attrib.bInheritHandle = TRUE;
379 s_attrib.lpSecurityDescriptor = NULL;
380 s_attrib.nLength = sizeof(s_attrib);
381 inst_count_mutex = CreateMutexA(&s_attrib,1,DDEInstanceAccess); /* 1st time through */
382 inst_count_mutex = ConvertToGlobalHandle(inst_count_mutex); /* fixme when having seperate adresspaces*/
384 if ( !WaitForMutex(inst_count_mutex) )
386 return DMLERR_SYS_ERROR;
389 if ( !inst_count_mutex )
391 ERR("CreateMutex failed - inst_count %li\n",GetLastError());
392 Release_reserved_mutex (handle_mutex,"handle_mutex",0,1,this_instance);
393 return DMLERR_SYS_ERROR;
395 DDE_Max_Assigned_Instance++;
396 this_instance->Instance_id = DDE_Max_Assigned_Instance;
397 TRACE("New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
398 if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0,this_instance)) return DMLERR_SYS_ERROR;
399 return DMLERR_NO_ERROR;
402 /******************************************************************************
403 * FindNotifyMonitorCallbacks
405 * Routine to find instances that need to be notified via their callback
406 * of some event they are monitoring
408 ******************************************************************************
412 * Vn Date Author Comment
414 * 1.0 May 1999 Keith Matthews Initial Version
418 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
420 DDE_HANDLE_ENTRY *InstanceHandle;
421 InstanceHandle = DDE_Handle_Table_Base;
422 while ( InstanceHandle != NULL )
424 if ( (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
426 /* Found an instance registered as monitor and is not ourselves
427 * use callback to notify where appropriate
430 InstanceHandle = InstanceHandle->Next_Entry;
434 /******************************************************************************
437 * Routine to make an extra Add on an atom to reserve it a bit longer
439 ******************************************************************************
443 * Vn Date Author Comment
445 * 1.0 Jun 1999 Keith Matthews Initial Version
449 static void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
451 if ( reference_inst->Unicode)
453 WCHAR SNameBuffer[MAX_BUFFER_LEN];
454 GlobalGetAtomNameW(hsz,SNameBuffer,MAX_BUFFER_LEN);
455 GlobalAddAtomW(SNameBuffer);
457 CHAR SNameBuffer[MAX_BUFFER_LEN];
458 GlobalGetAtomNameA(hsz,SNameBuffer,MAX_BUFFER_LEN);
459 GlobalAddAtomA(SNameBuffer);
464 /******************************************************************************
467 * Routine to make a delete on an atom to release it a bit sooner
469 ******************************************************************************
473 * Vn Date Author Comment
475 * 1.0 Jun 1999 Keith Matthews Initial Version
479 static void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
481 GlobalDeleteAtom( hsz );
484 /******************************************************************************
485 * DdeInitialize16 (DDEML.2)
487 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
488 DWORD afCmd, DWORD ulRes)
490 TRACE("DdeInitialize16 called - calling DdeInitializeA\n");
491 return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
496 /******************************************************************************
497 * DdeInitializeA (USER32.106)
499 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
500 DWORD afCmd, DWORD ulRes )
502 TRACE("DdeInitializeA called - calling DdeInitializeW\n");
503 return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
507 /******************************************************************************
508 * DdeInitializeW [USER32.107]
509 * Registers an application with the DDEML
512 * pidInst [I] Pointer to instance identifier
513 * pfnCallback [I] Pointer to callback function
514 * afCmd [I] Set of command and filter flags
518 * Success: DMLERR_NO_ERROR
519 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
521 ******************************************************************************
525 * Vn Date Author Comment
527 * 1.0 Pre 1998 Alexandre/Len Initial Stub
528 * 1.1 Jan 1999 Keith Matthews Initial (near-)complete version
529 * 1.2 Mar 1999 Keith Matthews Corrected Heap handling, CreateMutex failure handling
532 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
533 DWORD afCmd, DWORD ulRes )
536 /* probably not really capable of handling multiple processes, but should handle
537 * multiple instances within one process */
539 SECURITY_ATTRIBUTES *s_att= NULL;
540 SECURITY_ATTRIBUTES s_attrib;
542 DDE_HANDLE_ENTRY *this_instance;
543 DDE_HANDLE_ENTRY *reference_inst;
548 ERR("Reserved value not zero? What does this mean?\n");
549 FIXME("(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
551 /* trap this and no more until we know more */
552 return DMLERR_NO_ERROR;
556 /* this one may be wrong - MS dll seems to accept the condition,
557 leave this until we find out more !! */
560 /* can't set up the instance with nothing to act as a callback */
561 TRACE("No callback provided\n");
562 return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
565 /* grab enough heap for one control struct - not really necessary for re-initialise
566 * but allows us to use same validation routines */
567 this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( GetProcessHeap(), 0, sizeof(DDE_HANDLE_ENTRY) );
568 if ( this_instance == NULL )
570 /* catastrophe !! warn user & abort */
571 ERR("Instance create failed - out of memory\n");
572 return DMLERR_SYS_ERROR;
574 this_instance->Next_Entry = NULL;
575 this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
577 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
579 this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
580 this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
581 this_instance->CallBack=*pfnCallback;
582 this_instance->Txn_count=0;
583 this_instance->Unicode = TRUE;
584 this_instance->Win16 = FALSE;
585 this_instance->Node_list = NULL; /* node will be added later */
586 this_instance->Monitor_flags = afCmd & MF_MASK;
587 this_instance->ServiceNames = NULL;
589 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
591 this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
593 if ( ! this_instance->Client_only )
596 /* Check for other way of setting Client-only !! */
598 this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
599 ==CBF_FAIL_ALLSVRXACTIONS;
602 TRACE("instance created - checking validity \n");
604 if( *pidInst == 0 ) {
605 /* Initialisation of new Instance Identifier */
606 TRACE("new instance, callback %p flags %lX\n",pfnCallback,afCmd);
607 if ( DDE_Max_Assigned_Instance == 0 )
609 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
610 /* Need to set up Mutex in case it is not already present */
611 s_att->bInheritHandle = TRUE;
612 s_att->lpSecurityDescriptor = NULL;
613 s_att->nLength = sizeof(s_att);
614 handle_mutex = CreateMutexA(s_att,1,DDEHandleAccess);
615 handle_mutex = ConvertToGlobalHandle(handle_mutex); /* fixme when having seperate adresspaces*/
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;
628 TRACE("Handle Mutex created/reserved\n");
629 if (DDE_Handle_Table_Base == NULL )
631 /* can't be another instance in this case, assign to the base pointer */
632 DDE_Handle_Table_Base= this_instance;
634 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
636 * ------------------------------- NOTE NOTE NOTE --------------------------
638 * the manual is not clear if this condition
639 * applies to the first call to DdeInitialize from an application, or the
640 * first call for a given callback !!!
643 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
644 TRACE("First application instance detected OK\n");
645 /* allocate new instance ID */
646 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
649 /* really need to chain the new one in to the latest here, but after checking conditions
650 * such as trying to start a conversation from an application trying to monitor */
651 reference_inst = DDE_Handle_Table_Base;
652 TRACE("Subsequent application instance - starting checks\n");
653 while ( reference_inst->Next_Entry != NULL )
656 * This set of tests will work if application uses same instance Id
657 * at application level once allocated - which is what manual implies
658 * should happen. If someone tries to be
659 * clever (lazy ?) it will fail to pick up that later calls are for
660 * the same application - should we trust them ?
662 if ( this_instance->Instance_id == reference_inst->Instance_id)
664 /* Check 1 - must be same Client-only state */
666 if ( this_instance->Client_only != reference_inst->Client_only)
668 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
669 return DMLERR_SYS_ERROR;
670 return DMLERR_DLL_USAGE;
673 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
675 if ( this_instance->Monitor != reference_inst->Monitor)
677 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
678 return DMLERR_SYS_ERROR;
679 return DMLERR_INVALIDPARAMETER;
682 /* Check 3 - must supply different callback address */
684 if ( this_instance->CallBack == reference_inst->CallBack)
686 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
687 return DMLERR_SYS_ERROR;
688 return DMLERR_DLL_USAGE;
691 reference_inst = reference_inst->Next_Entry;
693 /* All cleared, add to chain */
695 TRACE("Application Instance checks finished\n");
696 if ((err_no = IncrementInstanceId( this_instance)) ) return err_no;
697 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0,this_instance)) return DMLERR_SYS_ERROR;
698 reference_inst->Next_Entry = this_instance;
700 *pidInst = this_instance->Instance_id;
701 TRACE("New application instance processing finished OK\n");
703 /* Reinitialisation situation --- FIX */
704 TRACE("reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
706 if ( !WaitForMutex(handle_mutex) )
708 HeapFree(GetProcessHeap(), 0, this_instance);
709 return DMLERR_SYS_ERROR;
712 if (DDE_Handle_Table_Base == NULL )
714 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance)) return DMLERR_SYS_ERROR;
715 return DMLERR_DLL_USAGE;
717 HeapFree(GetProcessHeap(), 0, this_instance); /* finished - release heap space used as work store */
718 /* can't reinitialise if we have initialised nothing !! */
719 reference_inst = DDE_Handle_Table_Base;
720 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
722 * MS allows initialisation without specifying a callback, should we allow addition of the
723 * callback by a later call to initialise ? - if so this lot will have to change
725 while ( reference_inst->Next_Entry != NULL )
727 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
729 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
731 if ( reference_inst->Client_only )
733 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
735 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
737 if ( ! ( afCmd & APPCMD_CLIENTONLY))
739 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
740 return DMLERR_SYS_ERROR;
741 return DMLERR_DLL_USAGE;
745 /* Check 2 - cannot change monitor modes */
747 if ( this_instance->Monitor != reference_inst->Monitor)
749 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
750 return DMLERR_SYS_ERROR;
751 return DMLERR_DLL_USAGE;
754 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
756 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
758 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
759 return DMLERR_SYS_ERROR;
760 return DMLERR_DLL_USAGE;
764 reference_inst = reference_inst->Next_Entry;
766 if ( reference_inst->Next_Entry == NULL )
768 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
770 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
772 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
773 return DMLERR_SYS_ERROR;
774 return DMLERR_INVALIDPARAMETER;
776 /* All checked - change relevant flags */
778 reference_inst->CBF_Flags = this_instance->CBF_Flags;
779 reference_inst->Client_only = this_instance->Client_only;
780 reference_inst->Monitor_flags = this_instance->Monitor_flags;
781 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1,this_instance))
782 return DMLERR_SYS_ERROR;
785 return DMLERR_NO_ERROR;
789 /*****************************************************************
790 * DdeUninitialize16 (DDEML.3)
792 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
794 FIXME(" stub calling DdeUninitialize\n");
795 return (BOOL16)DdeUninitialize( idInst );
799 /*****************************************************************
800 * DdeUninitialize [USER32.119] Frees DDEML resources
803 * idInst [I] Instance identifier
810 BOOL WINAPI DdeUninitialize( DWORD idInst )
812 /* Stage one - check if we have a handle for this instance
814 SECURITY_ATTRIBUTES *s_att= NULL;
815 SECURITY_ATTRIBUTES s_attrib;
816 DDE_HANDLE_ENTRY *this_instance;
817 DDE_HANDLE_ENTRY *reference_inst;
820 if ( DDE_Max_Assigned_Instance == 0 )
822 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
826 if ( !WaitForMutex(handle_mutex) )
828 return DMLERR_SYS_ERROR;
830 TRACE("Handle Mutex created/reserved\n");
831 /* First check instance
833 this_instance = Find_Instance_Entry(idInst);
834 if ( this_instance == NULL )
836 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return FALSE;
838 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
842 FIXME("(%ld): partial stub\n", idInst);
844 /* FIXME ++++++++++++++++++++++++++++++++++++++++++
845 * Needs to de-register all service names
848 /* Free the nodes that were not freed by this instance
849 * and remove the nodes from the list of HSZ nodes.
851 FreeAndRemoveHSZNodes( idInst, this_instance );
853 /* OK now delete the instance handle itself */
855 if ( DDE_Handle_Table_Base == this_instance )
857 /* special case - the first/only entry
859 DDE_Handle_Table_Base = this_instance->Next_Entry;
864 reference_inst = DDE_Handle_Table_Base;
865 while ( reference_inst->Next_Entry != this_instance )
867 reference_inst = this_instance->Next_Entry;
869 reference_inst->Next_Entry = this_instance->Next_Entry;
871 /* release the mutex and the heap entry
873 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE,this_instance))
875 /* should record something here, but nothing left to hang it from !!
883 /*****************************************************************
884 * DdeConnectList16 [DDEML.4]
887 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
888 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
890 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
895 /******************************************************************************
896 * DdeConnectList [USER32.93] Establishes conversation with DDE servers
899 * idInst [I] Instance identifier
900 * hszService [I] Handle to service name string
901 * hszTopic [I] Handle to topic name string
902 * hConvList [I] Handle to conversation list
903 * pCC [I] Pointer to structure with context data
906 * Success: Handle to new conversation list
909 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
910 HCONVLIST hConvList, LPCONVCONTEXT pCC )
912 FIXME("(%ld,%d,%d,%d,%p): stub\n", idInst, hszService, hszTopic,
918 /*****************************************************************
919 * DdeQueryNextServer16 [DDEML.5]
921 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
923 return DdeQueryNextServer(hConvList, hConvPrev);
927 /*****************************************************************
928 * DdeQueryNextServer [USER32.112]
930 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
932 FIXME("(%d,%d): stub\n",hConvList,hConvPrev);
936 /*****************************************************************
937 * DdeQueryStringA [USER32.113]
939 *****************************************************************
943 * Vn Date Author Comment
945 * 1.0 Dec 1998 Corel/Macadamian Initial version
946 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
949 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
952 CHAR pString[MAX_BUFFER_LEN];
953 DDE_HANDLE_ENTRY *reference_inst;
956 "(%ld, 0x%x, %p, %ld, %d): partial stub\n",
962 if ( DDE_Max_Assigned_Instance == 0 )
964 /* Nothing has been initialised - exit now ! */
965 /* needs something for DdeGetLAstError even if the manual doesn't say so */
969 if ( !WaitForMutex(handle_mutex) )
974 TRACE("Handle Mutex created/reserved\n");
976 /* First check instance
978 reference_inst = Find_Instance_Entry(idInst);
979 if ( reference_inst == NULL )
981 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
983 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
988 if( iCodePage == CP_WINANSI )
990 /* If psz is null, we have to return only the length
996 cchMax = MAX_BUFFER_LEN;
999 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
1001 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1003 TRACE("returning pointer\n");
1007 /*****************************************************************
1008 * DdeQueryStringW [USER32.114]
1010 *****************************************************************
1014 * Vn Date Author Comment
1016 * 1.0 Dec 1998 Corel/Macadamian Initial version
1020 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1023 WCHAR pString[MAX_BUFFER_LEN];
1027 "(%ld, 0x%x, %p, %ld, %d): stub\n",
1034 if( iCodePage == CP_WINUNICODE )
1036 /* If psz is null, we have to return only the length
1042 cchMax = MAX_BUFFER_LEN;
1043 /* Note: According to documentation if the psz parameter
1044 * was NULL this API must return the length of the string in bytes.
1046 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1048 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1053 /*****************************************************************
1055 * DdeQueryString16 (DDEML.23)
1057 ******************************************************************
1061 * Vn Date Author Comment
1063 * 1.0 March 1999 K Matthews stub only
1066 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, INT16 codepage)
1068 FIXME("(%ld, 0x%x, %p, %ld, %d): stub \n",
1078 /*****************************************************************
1079 * DdeDisconnectList (DDEML.6)
1081 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1083 return (BOOL16)DdeDisconnectList(hConvList);
1087 /******************************************************************************
1088 * DdeDisconnectList [USER32.98] Destroys list and terminates conversations
1094 BOOL WINAPI DdeDisconnectList(
1095 HCONVLIST hConvList) /* [in] Handle to conversation list */
1097 FIXME("(%d): stub\n", hConvList);
1102 /*****************************************************************
1103 * DdeConnect16 (DDEML.7)
1105 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1106 LPCONVCONTEXT16 pCC )
1108 FIXME("empty stub\n" );
1113 /*****************************************************************
1114 * DdeConnect (USER32.92)
1116 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1119 FIXME("(0x%lx,%d,%d,%p): stub\n",idInst,hszService,hszTopic,
1125 /*****************************************************************
1126 * DdeDisconnect16 (DDEML.8)
1128 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1130 return (BOOL16)DdeDisconnect( hConv );
1133 /*****************************************************************
1134 * DdeSetUserHandle16 (DDEML.10)
1136 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1138 FIXME("(%d,%ld,%ld): stub\n",hConv,id, hUser );
1142 /*****************************************************************
1143 * DdeCreateDataHandle16 (DDEML.14)
1145 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
1146 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
1149 return DdeCreateDataHandle(idInst,
1158 /*****************************************************************
1159 * DdeCreateDataHandle (USER32.94)
1161 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
1162 DWORD cbOff, HSZ hszItem, UINT wFmt,
1166 "(%ld,%p,%ld,%ld,0x%x,%d,%d): stub\n",
1178 /*****************************************************************
1179 * DdeDisconnect (USER32.97)
1181 BOOL WINAPI DdeDisconnect( HCONV hConv )
1183 FIXME("empty stub\n" );
1188 /*****************************************************************
1189 * DdeReconnect (DDEML.37) (USER32.115)
1191 HCONV WINAPI DdeReconnect( HCONV hConv )
1193 FIXME("empty stub\n" );
1198 /*****************************************************************
1199 * DdeCreateStringHandle16 (DDEML.21)
1201 *****************************************************************
1205 * Vn Date Author Comment
1207 * 1.0 ? ? basic stub
1208 * 1.1 June 1999 Keith Matthews amended onward call to supply default
1209 * code page if none supplied by caller
1211 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1215 return DdeCreateStringHandleA( idInst, str, codepage );
1217 TRACE("Default codepage supplied\n");
1218 return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1223 /*****************************************************************
1224 * DdeCreateStringHandleA [USER32.95]
1227 * Success: String handle
1230 *****************************************************************
1234 * Vn Date Author Comment
1236 * 1.0 Dec 1998 Corel/Macadamian Initial version
1237 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1240 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1243 DDE_HANDLE_ENTRY *reference_inst;
1244 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1247 if ( DDE_Max_Assigned_Instance == 0 )
1249 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1253 if ( !WaitForMutex(handle_mutex) )
1255 return DMLERR_SYS_ERROR;
1258 TRACE("Handle Mutex created/reserved\n");
1260 /* First check instance
1262 reference_inst = Find_Instance_Entry(idInst);
1263 if ( reference_inst == NULL )
1265 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1267 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1272 if (codepage==CP_WINANSI)
1274 hsz = GlobalAddAtomA (psz);
1275 /* Save the handle so we know to clean it when
1276 * uninitialize is called.
1278 TRACE("added atom %s with HSZ 0x%x, \n",debugstr_a(psz),hsz);
1279 InsertHSZNode( hsz, reference_inst );
1280 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1282 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1285 TRACE("Returning pointer\n");
1288 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1290 TRACE("Returning error\n");
1295 /******************************************************************************
1296 * DdeCreateStringHandleW [USER32.96] Creates handle to identify string
1299 * Success: String handle
1302 *****************************************************************
1306 * Vn Date Author Comment
1308 * 1.0 Dec 1998 Corel/Macadamian Initial version
1309 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1312 HSZ WINAPI DdeCreateStringHandleW(
1313 DWORD idInst, /* [in] Instance identifier */
1314 LPCWSTR psz, /* [in] Pointer to string */
1315 INT codepage) /* [in] Code page identifier */
1317 DDE_HANDLE_ENTRY *reference_inst;
1320 TRACE("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1323 if ( DDE_Max_Assigned_Instance == 0 )
1325 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1329 if ( !WaitForMutex(handle_mutex) )
1331 return DMLERR_SYS_ERROR;
1334 TRACE("CreateString - Handle Mutex created/reserved\n");
1336 /* First check instance
1338 reference_inst = Find_Instance_Entry(idInst);
1339 if ( reference_inst == NULL )
1341 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return 0;
1343 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1348 FIXME("(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1350 if (codepage==CP_WINUNICODE)
1352 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1355 hsz = GlobalAddAtomW (psz);
1356 /* Save the handle so we know to clean it when
1357 * uninitialize is called.
1359 InsertHSZNode( hsz, reference_inst );
1360 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst))
1362 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1365 TRACE("Returning pointer\n");
1368 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1370 TRACE("Returning error\n");
1375 /*****************************************************************
1376 * DdeFreeStringHandle16 (DDEML.22)
1378 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1380 FIXME("idInst %ld hsz 0x%x\n",idInst,hsz);
1381 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1385 /*****************************************************************
1386 * DdeFreeStringHandle (USER32.101)
1387 * RETURNS: success: nonzero
1390 *****************************************************************
1394 * Vn Date Author Comment
1396 * 1.0 Dec 1998 Corel/Macadamian Initial version
1397 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1400 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1402 DDE_HANDLE_ENTRY *reference_inst;
1403 TRACE("(%ld,%d): \n",idInst,hsz);
1404 if ( DDE_Max_Assigned_Instance == 0 )
1406 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1410 if ( !WaitForMutex(handle_mutex) )
1412 return DMLERR_SYS_ERROR;
1415 TRACE("Handle Mutex created/reserved\n");
1417 /* First check instance
1419 reference_inst = Find_Instance_Entry(idInst);
1420 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1422 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
1423 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1428 /* Remove the node associated with this HSZ.
1430 RemoveHSZNode( hsz , reference_inst);
1431 /* Free the string associated with this HSZ.
1433 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1434 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1438 /*****************************************************************
1439 * DdeFreeDataHandle16 (DDEML.19)
1441 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1443 return (BOOL)DdeFreeDataHandle( hData );
1447 /*****************************************************************
1448 * DdeFreeDataHandle (USER32.100)
1450 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1452 FIXME("empty stub\n" );
1459 /*****************************************************************
1460 * DdeKeepStringHandle16 (DDEML.24)
1462 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1464 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1468 /*****************************************************************
1469 * DdeKeepStringHandle (USER32.108)
1471 * RETURNS: success: nonzero
1474 *****************************************************************
1478 * Vn Date Author Comment
1481 * 1.1 Jun 1999 Keith Matthews First cut implementation
1484 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1487 DDE_HANDLE_ENTRY *reference_inst;
1488 TRACE("(%ld,%d): \n",idInst,hsz);
1489 if ( DDE_Max_Assigned_Instance == 0 )
1491 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1496 if ( !WaitForMutex(handle_mutex) )
1501 TRACE("Handle Mutex created/reserved\n");
1503 /* First check instance
1505 reference_inst = Find_Instance_Entry(idInst);
1506 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1508 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return FALSE;
1509 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1513 DdeReserveAtom(reference_inst,hsz);
1514 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
1519 /*****************************************************************
1520 * DdeClientTransaction16 (DDEML.11)
1522 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1523 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1524 UINT16 wType, DWORD dwTimeout,
1527 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1528 wFmt, wType, dwTimeout, pdwResult );
1532 /*****************************************************************
1533 * DdeClientTransaction (USER32.90)
1535 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1536 HCONV hConv, HSZ hszItem, UINT wFmt,
1537 UINT wType, DWORD dwTimeout,
1540 FIXME("empty stub\n" );
1544 /*****************************************************************
1546 * DdeAbandonTransaction16 (DDEML.12)
1549 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1550 DWORD idTransaction )
1552 FIXME("empty stub\n" );
1557 /*****************************************************************
1559 * DdeAbandonTransaction (USER32.87)
1561 ******************************************************************
1565 * Vn Date Author Comment
1567 * 1.0 March 1999 K Matthews stub only
1569 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1570 DWORD idTransaction )
1572 FIXME("empty stub\n" );
1576 /*****************************************************************
1577 * DdePostAdvise16 [DDEML.13]
1579 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1581 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1585 /******************************************************************************
1586 * DdePostAdvise [USER32.110] Send transaction to DDE callback function.
1592 BOOL WINAPI DdePostAdvise(
1593 DWORD idInst, /* [in] Instance identifier */
1594 HSZ hszTopic, /* [in] Handle to topic name string */
1595 HSZ hszItem) /* [in] Handle to item name string */
1597 FIXME("(%ld,%d,%d): stub\n",idInst,hszTopic,hszItem);
1602 /*****************************************************************
1603 * DdeAddData16 (DDEML.15)
1605 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1608 FIXME("empty stub\n" );
1612 /*****************************************************************
1614 * DdeAddData (USER32.89)
1616 ******************************************************************
1620 * Vn Date Author Comment
1622 * 1.0 March 1999 K Matthews stub only
1624 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1627 FIXME("empty stub\n" );
1632 /*****************************************************************
1634 * DdeImpersonateClient (USER32.105)
1636 ******************************************************************
1640 * Vn Date Author Comment
1642 * 1.0 March 1999 K Matthews stub only
1645 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1647 FIXME("empty stub\n" );
1652 /*****************************************************************
1654 * DdeSetQualityOfService (USER32.116)
1656 ******************************************************************
1660 * Vn Date Author Comment
1662 * 1.0 March 1999 K Matthews stub only
1665 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1666 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1668 FIXME("empty stub\n" );
1672 /*****************************************************************
1674 * DdeSetUserHandle (USER32.117)
1676 ******************************************************************
1680 * Vn Date Author Comment
1682 * 1.0 March 1999 K Matthews stub only
1685 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1687 FIXME("empty stub\n" );
1691 /******************************************************************************
1692 * DdeGetData [USER32.102] Copies data from DDE object ot local buffer
1695 * Size of memory object associated with handle
1697 DWORD WINAPI DdeGetData(
1698 HDDEDATA hData, /* [in] Handle to DDE object */
1699 LPBYTE pDst, /* [in] Pointer to destination buffer */
1700 DWORD cbMax, /* [in] Amount of data to copy */
1701 DWORD cbOff) /* [in] Offset to beginning of data */
1703 FIXME("(%d,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1708 /*****************************************************************
1709 * DdeGetData16 [DDEML.16]
1711 DWORD WINAPI DdeGetData16(
1717 return DdeGetData(hData, pDst, cbMax, cbOff);
1721 /*****************************************************************
1722 * DdeAccessData16 (DDEML.17)
1724 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1726 return DdeAccessData(hData, pcbDataSize);
1729 /*****************************************************************
1730 * DdeAccessData (USER32.88)
1732 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1734 FIXME("(%d,%p): stub\n", hData, pcbDataSize);
1738 /*****************************************************************
1739 * DdeUnaccessData16 (DDEML.18)
1741 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1743 return DdeUnaccessData(hData);
1746 /*****************************************************************
1747 * DdeUnaccessData (USER32.118)
1749 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1751 FIXME("(0x%x): stub\n", hData);
1756 /*****************************************************************
1757 * DdeEnableCallback16 (DDEML.26)
1759 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1761 return DdeEnableCallback(idInst, hConv, wCmd);
1764 /*****************************************************************
1765 * DdeEnableCallback (USER32.99)
1767 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1769 FIXME("(%ld, 0x%x, %d) stub\n", idInst, hConv, wCmd);
1774 /*****************************************************************
1775 * DdeNameService16 (DDEML.27)
1777 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1780 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1784 /******************************************************************************
1785 * DdeNameService [USER32.109] {Un}registers service name of DDE server
1788 * idInst [I] Instance identifier
1789 * hsz1 [I] Handle to service name string
1791 * afCmd [I] Service name flags
1797 *****************************************************************
1801 * Vn Date Author Comment
1804 * 1.1 Apr 1999 Keith Matthews Added trap for non-existent instance (uninitialised instance 0
1805 * used by some MS programs for unfathomable reasons)
1806 * 1.2 May 1999 Keith Matthews Added parameter validation and basic service name handling.
1807 * Still needs callback parts
1810 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1813 ServiceNode* this_service, *reference_service ;
1814 DDE_HANDLE_ENTRY *this_instance;
1815 DDE_HANDLE_ENTRY *reference_inst;
1816 this_service = NULL;
1818 FIXME("(%ld,%d,%d,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1820 if ( DDE_Max_Assigned_Instance == 0 )
1822 /* Nothing has been initialised - exit now !
1823 * needs something for DdeGetLastError */
1827 if ( !WaitForMutex(handle_mutex) )
1829 return DMLERR_SYS_ERROR;
1832 TRACE("Handle Mutex created/reserved\n");
1834 /* First check instance
1836 reference_inst = Find_Instance_Entry(idInst);
1837 this_instance = reference_inst;
1838 if (reference_inst == NULL)
1840 TRACE("Instance not found as initialised\n");
1841 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance)) return TRUE;
1842 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1849 /* Illegal, reserved parameter
1851 reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1852 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1853 FIXME("Reserved parameter no-zero !!\n");
1859 * General unregister situation
1861 if ( afCmd != DNS_UNREGISTER )
1863 /* don't know if we should check this but it makes sense
1864 * why supply REGISTER or filter flags if de-registering all
1866 TRACE("General unregister unexpected flags\n");
1867 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1868 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1871 /* Loop to find all registered service and de-register them
1873 if ( reference_inst->ServiceNames == NULL )
1875 /* None to unregister !!
1877 TRACE("General de-register - nothing registered\n");
1878 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1879 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1883 this_service = reference_inst->ServiceNames;
1884 while ( this_service->next != NULL)
1886 TRACE("general deregister - iteration\n");
1887 reference_service = this_service;
1888 this_service = this_service->next;
1889 DdeReleaseAtom(reference_inst,reference_service->hsz);
1890 HeapFree(GetProcessHeap(), 0, reference_service); /* finished - release heap space used as work store */
1892 DdeReleaseAtom(reference_inst,this_service->hsz);
1893 HeapFree(GetProcessHeap(), 0, this_service); /* finished - release heap space used as work store */
1894 reference_inst->ServiceNames = NULL;
1895 TRACE("General de-register - finished\n");
1897 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1900 TRACE("Specific name action detected\n");
1901 if ( afCmd & DNS_REGISTER )
1903 /* Register new service name
1906 this_service = Find_Service_Name( hsz1, reference_inst );
1908 ERR("Trying to register already registered service!\n");
1911 TRACE("Adding service name\n");
1913 DdeReserveAtom(reference_inst, hsz1);
1915 this_service = (ServiceNode*)HeapAlloc( GetProcessHeap(), 0, sizeof(ServiceNode) );
1916 this_service->hsz = hsz1;
1917 this_service->FilterOn = TRUE;
1919 this_service->next = reference_inst->ServiceNames;
1920 reference_inst->ServiceNames = this_service;
1923 if ( afCmd & DNS_UNREGISTER )
1925 /* De-register service name
1928 ServiceNode **pServiceNode = &reference_inst->ServiceNames;
1929 while ( *pServiceNode && (*pServiceNode)->hsz != hsz1 )
1930 pServiceNode = &(*pServiceNode)->next;
1932 this_service = *pServiceNode;
1933 if ( !this_service )
1934 ERR("Trying to de-register unregistered service!\n");
1937 *pServiceNode = this_service->next;
1938 DdeReleaseAtom(reference_inst,this_service->hsz);
1939 HeapFree(GetProcessHeap(), 0, this_service);
1942 if ( afCmd & DNS_FILTERON )
1944 /* Set filter flags on to hold notifications of connection
1946 * test coded this way as this is the default setting
1948 this_service = Find_Service_Name( hsz1, reference_inst );
1949 if ( !this_service )
1951 /* trying to filter where no service names !!
1953 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1954 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1958 this_service->FilterOn = TRUE;
1961 if ( afCmd & DNS_FILTEROFF )
1963 /* Set filter flags on to hold notifications of connection
1965 this_service = Find_Service_Name( hsz1, reference_inst );
1966 if ( !this_service )
1968 /* trying to filter where no service names !!
1970 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1971 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1975 this_service->FilterOn = FALSE;
1978 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,this_instance);
1983 /*****************************************************************
1984 * DdeGetLastError16 (DDEML.20)
1986 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1988 return (UINT16)DdeGetLastError( idInst );
1992 /******************************************************************************
1993 * DdeGetLastError [USER32.103] Gets most recent error code
1996 * idInst [I] Instance identifier
2001 *****************************************************************
2005 * Vn Date Author Comment
2008 * 1.1 Apr 1999 Keith Matthews Added response for non-existent instance (uninitialised instance 0
2009 * used by some MS programs for unfathomable reasons)
2010 * 1.2 May 1999 Keith Matthews Added interrogation of Last_Error for instance handle where found.
2013 UINT WINAPI DdeGetLastError( DWORD idInst )
2016 DDE_HANDLE_ENTRY *reference_inst;
2018 FIXME("(%ld): stub\n",idInst);
2020 if ( DDE_Max_Assigned_Instance == 0 )
2022 /* Nothing has been initialised - exit now ! */
2023 return DMLERR_DLL_NOT_INITIALIZED;
2026 if ( !WaitForMutex(handle_mutex) )
2028 return DMLERR_SYS_ERROR;
2031 TRACE("Handle Mutex created/reserved\n");
2033 /* First check instance
2035 reference_inst = Find_Instance_Entry(idInst);
2036 if (reference_inst == NULL)
2038 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst)) return TRUE;
2039 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2040 return DMLERR_DLL_NOT_INITIALIZED;
2043 error_code = reference_inst->Last_Error;
2044 reference_inst->Last_Error = 0;
2045 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE,reference_inst);
2050 /*****************************************************************
2051 * DdeCmpStringHandles16 (DDEML.36)
2053 INT16 WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2055 return DdeCmpStringHandles(hsz1, hsz2);
2058 /*****************************************************************
2059 * DdeCmpStringHandles (USER32.91)
2061 * Compares the value of two string handles. This comparison is
2062 * not case sensitive.
2065 * -1 The value of hsz1 is zero or less than hsz2
2066 * 0 The values of hsz 1 and 2 are the same or both zero.
2067 * 1 The value of hsz2 is zero of less than hsz1
2069 INT WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2071 CHAR psz1[MAX_BUFFER_LEN];
2072 CHAR psz2[MAX_BUFFER_LEN];
2076 TRACE("handle 1, handle 2\n" );
2078 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2079 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2080 /* Make sure we found both strings.
2082 if( ret1 == 0 && ret2 == 0 )
2084 /* If both are not found, return both "zero strings".
2088 else if( ret1 == 0 )
2090 /* If hsz1 is a not found, return hsz1 is "zero string".
2094 else if( ret2 == 0 )
2096 /* If hsz2 is a not found, return hsz2 is "zero string".
2102 /* Compare the two strings we got ( case insensitive ).
2104 ret = strcasecmp( psz1, psz2 );
2105 /* Since strcmp returns any number smaller than
2106 * 0 when the first string is found to be less than
2107 * the second one we must make sure we are returning
2108 * the proper values.
2123 /*****************************************************************
2124 * PackDDElParam (USER32.414)
2130 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2137 /*****************************************************************
2138 * UnpackDDElParam (USER32.562)
2144 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
2145 UINT *uiLo, UINT *uiHi)
2152 /*****************************************************************
2153 * FreeDDElParam (USER32.204)
2159 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
2165 /*****************************************************************
2166 * ReuseDDElParam (USER32.446)
2169 UINT 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.111)
2191 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)