4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1997 Len White
6 * Copyright 1999 Keith Matthews
9 /* Only empty stubs for now */
18 #include "shm_semaph.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 inst_string[]= "DDEMaxInstance";
81 static LPCWSTR DDEInstanceAccess = (LPCWSTR)&inst_string;
82 static const char handle_string[] = "DDEHandleAccess";
83 static LPCWSTR DDEHandleAccess = (LPCWSTR)&handle_string;
84 static HANDLE inst_count_mutex = 0;
85 static HANDLE handle_mutex = 0;
86 DDE_HANDLE_ENTRY *this_instance;
87 SECURITY_ATTRIBUTES *s_att= NULL;
90 DDE_HANDLE_ENTRY *reference_inst;
96 /******************************************************************************
97 * RemoveHSZNodes (INTERNAL)
99 * Remove a node from the list of HSZ nodes.
101 ******************************************************************************
105 * Vn Date Author Comment
107 * 1.0 Dec 1998 Corel/Macadamian Initial version
108 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
111 static void RemoveHSZNode( HSZ hsz )
113 HSZNode* pPrev = NULL;
114 HSZNode* pCurrent = NULL;
116 /* Set the current node at the start of the list.
118 pCurrent = reference_inst->Node_list;
119 /* While we have more nodes.
121 while( pCurrent != NULL )
123 /* If we found the node we were looking for.
125 if( pCurrent->hsz == hsz )
129 /* If the first node in the list is to to be removed.
130 * Set the global list pointer to the next node.
132 if( pCurrent == reference_inst->Node_list )
134 reference_inst->Node_list = pCurrent->next;
136 /* Just fix the pointers has to skip the current
137 * node so we can delete it.
141 pPrev->next = pCurrent->next;
143 /* Destroy this node.
148 /* Save the previous node pointer.
151 /* Move on to the next node.
153 pCurrent = pCurrent->next;
157 /******************************************************************************
158 * FreeAndRemoveHSZNodes (INTERNAL)
160 * Frees up all the strings still allocated in the list and
161 * remove all the nodes from the list of HSZ nodes.
163 ******************************************************************************
167 * Vn Date Author Comment
169 * 1.0 Dec 1998 Corel/Macadamian Initial version
170 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
173 static void FreeAndRemoveHSZNodes( DWORD idInst )
175 /* Free any strings created in this instance.
177 while( reference_inst->Node_list != NULL )
179 DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
183 /******************************************************************************
184 * InsertHSZNode (INTERNAL)
186 * Insert a node to the head of the list.
188 ******************************************************************************
192 * Vn Date Author Comment
194 * 1.0 Dec 1998 Corel/Macadamian Initial version
195 * 1.1 Mar 1999 Keith Matthews Added instance handling
196 * 1.2 Jun 1999 Keith Matthews Added Usage count handling
199 static void InsertHSZNode( HSZ hsz )
203 HSZNode* pNew = NULL;
204 /* Create a new node for this HSZ.
206 pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
209 /* Set the handle value.
212 /* Attach the node to the head of the list. i.e most recently added is first
214 pNew->next = reference_inst->Node_list;
216 /* The new node is now at the head of the list
217 * so set the global list pointer to it.
219 reference_inst->Node_list = pNew;
220 TRACE(ddeml,"HSZ node list entry added\n");
225 /*****************************************************************************
226 * Find_Instance_Entry
228 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
229 * for an instance Id, or NULL if the entry does not exist
231 * ASSUMES the mutex protecting the handle entry list is reserved before calling
233 ******************************************************************************
237 * Vn Date Author Comment
239 * 1.0 March 1999 Keith Matthews 1st implementation
241 DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
243 reference_inst = DDE_Handle_Table_Base;
244 while ( reference_inst != NULL )
246 if ( reference_inst->Instance_id == InstId )
248 TRACE(ddeml,"Instance entry found\n");
249 return reference_inst;
251 reference_inst = reference_inst->Next_Entry;
253 TRACE(ddeml,"Instance entry missing\n");
257 /*****************************************************************************
260 * generic routine to return a pointer to the relevant ServiceNode
261 * for a given service name, or NULL if the entry does not exist
263 * ASSUMES the mutex protecting the handle entry list is reserved before calling
265 ******************************************************************************
269 * Vn Date Author Comment
271 * 1.0 May 1999 Keith Matthews 1st implementation
273 ServiceNode *Find_Service_Name (HSZ Service_Name, DDE_HANDLE_ENTRY* this_instance)
275 ServiceNode * reference_name= this_instance->ServiceNames;
276 while ( reference_name != NULL )
278 if ( reference_name->hsz == Service_Name )
280 TRACE(ddeml,"Service Name found\n");
281 return reference_name;
283 reference_name = reference_name->next;
285 TRACE(ddeml,"Service name missing\n");
290 /******************************************************************************
291 * Release_reserved_mutex
293 * generic routine to release a reserved mutex
296 ******************************************************************************
300 * Vn Date Author Comment
302 * 1.0 Jan 1999 Keith Matthews Initial version
303 * 1.1 Mar 1999 Keith Matthews Corrected Heap handling. Corrected re-initialisation handling
306 static DWORD Release_reserved_mutex (HANDLE mutex, LPSTR mutex_name, BOOL release_handle_m, BOOL release_this_i )
309 if ( (err_no=GetLastError()) != 0 )
311 ERR(ddeml,"ReleaseMutex failed - %s mutex %li\n",mutex_name,err_no);
312 HeapFree(SystemHeap, 0, this_instance);
313 if ( release_handle_m )
315 ReleaseMutex(handle_mutex);
317 return DMLERR_SYS_ERROR;
319 if ( release_this_i )
321 HeapFree(SystemHeap, 0, this_instance);
323 return DMLERR_NO_ERROR;
326 /******************************************************************************
327 * IncrementInstanceId
329 * generic routine to increment the max instance Id and allocate a new application instance
331 ******************************************************************************
335 * Vn Date Author Comment
337 * 1.0 Jan 1999 Keith Matthews Initial version
340 DWORD IncrementInstanceId()
342 SECURITY_ATTRIBUTES s_attrib;
343 /* Need to set up Mutex in case it is not already present */
344 /* increment handle count & get value */
345 if ( !inst_count_mutex )
347 s_attrib.bInheritHandle = TRUE;
348 s_attrib.lpSecurityDescriptor = NULL;
349 s_attrib.nLength = sizeof(s_attrib);
350 inst_count_mutex = CreateMutexW(&s_attrib,1,DDEInstanceAccess); /* 1st time through */
352 WaitForSingleObject(inst_count_mutex,1000); /* subsequent calls */
353 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
355 if ( (err_no=GetLastError()) != 0 )
357 ERR(ddeml,"CreateMutex failed - inst_count %li\n",err_no);
358 err_no=Release_reserved_mutex (handle_mutex,"handle_mutex",0,1);
359 return DMLERR_SYS_ERROR;
361 DDE_Max_Assigned_Instance++;
362 this_instance->Instance_id = DDE_Max_Assigned_Instance;
363 TRACE(ddeml,"New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
364 if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0)) return DMLERR_SYS_ERROR;
365 return DMLERR_NO_ERROR;
368 /******************************************************************************
369 * FindNotifyMonitorCallbacks
371 * Routine to find instances that need to be notified via their callback
372 * of some event they are monitoring
374 ******************************************************************************
378 * Vn Date Author Comment
380 * 1.0 May 1999 Keith Matthews Initial Version
384 void FindNotifyMonitorCallbacks(DWORD ThisInstance, DWORD DdeEvent )
386 DDE_HANDLE_ENTRY *InstanceHandle;
387 InstanceHandle = DDE_Handle_Table_Base;
388 while ( InstanceHandle != NULL )
390 if ( (InstanceHandle->Monitor ) && InstanceHandle->Instance_id == ThisInstance )
392 /* Found an instance registered as monitor and is not ourselves
393 * use callback to notify where appropriate
396 InstanceHandle = InstanceHandle->Next_Entry;
400 /******************************************************************************
403 * Routine to make an extra Add on an atom to reserve it a bit longer
405 ******************************************************************************
409 * Vn Date Author Comment
411 * 1.0 Jun 1999 Keith Matthews Initial Version
415 void DdeReserveAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
417 CHAR SNameBuffer[MAX_BUFFER_LEN];
419 if ( reference_inst->Unicode)
421 rcode=GlobalGetAtomNameW(hsz,(LPWSTR)&SNameBuffer,MAX_ATOM_LEN);
422 GlobalAddAtomW((LPWSTR)SNameBuffer);
424 rcode=GlobalGetAtomNameA(hsz,SNameBuffer,MAX_ATOM_LEN);
425 GlobalAddAtomA(SNameBuffer);
430 /******************************************************************************
433 * Routine to make a delete on an atom to release it a bit sooner
435 ******************************************************************************
439 * Vn Date Author Comment
441 * 1.0 Jun 1999 Keith Matthews Initial Version
445 void DdeReleaseAtom( DDE_HANDLE_ENTRY * reference_inst,HSZ hsz)
447 CHAR SNameBuffer[MAX_BUFFER_LEN];
449 if ( reference_inst->Unicode)
451 rcode=GlobalGetAtomNameW(hsz,(LPWSTR)&SNameBuffer,MAX_ATOM_LEN);
452 GlobalAddAtomW((LPWSTR)SNameBuffer);
454 rcode=GlobalGetAtomNameA(hsz,SNameBuffer,MAX_ATOM_LEN);
455 GlobalAddAtomA(SNameBuffer);
459 /******************************************************************************
460 * DdeInitialize16 (DDEML.2)
462 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
463 DWORD afCmd, DWORD ulRes)
465 TRACE(ddeml,"DdeInitialize16 called - calling DdeInitializeA\n");
466 return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
471 /******************************************************************************
472 * DdeInitializeA (USER32.106)
474 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
475 DWORD afCmd, DWORD ulRes )
477 TRACE(ddeml,"DdeInitializeA called - calling DdeInitializeW\n");
478 return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
482 /******************************************************************************
483 * DdeInitializeW [USER32.107]
484 * Registers an application with the DDEML
487 * pidInst [I] Pointer to instance identifier
488 * pfnCallback [I] Pointer to callback function
489 * afCmd [I] Set of command and filter flags
493 * Success: DMLERR_NO_ERROR
494 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
496 ******************************************************************************
500 * Vn Date Author Comment
502 * 1.0 Pre 1998 Alexandre/Len Initial Stub
503 * 1.1 Jan 1999 Keith Matthews Initial (near-)complete version
504 * 1.2 Mar 1999 Keith Matthews Corrected Heap handling, CreateMutex failure handling
507 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
508 DWORD afCmd, DWORD ulRes )
511 /* probably not really capable of handling mutliple processes, but should handle
512 * multiple instances within one process */
514 SECURITY_ATTRIBUTES s_attrib;
519 ERR(ddeml, "Reserved value not zero? What does this mean?\n");
520 FIXME(ddeml, "(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
522 /* trap this and no more until we know more */
523 return DMLERR_NO_ERROR;
527 /* this one may be wrong - MS dll seems to accept the condition,
528 leave this until we find out more !! */
531 /* can't set up the instance with nothing to act as a callback */
532 TRACE(ddeml,"No callback provided\n");
533 return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
536 /* grab enough heap for one control struct - not really necessary for re-initialise
537 * but allows us to use same validation routines */
538 this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( SystemHeap, 0, sizeof(DDE_HANDLE_ENTRY) );
539 if ( this_instance == NULL )
541 /* catastrophe !! warn user & abort */
542 ERR (ddeml, "Instance create failed - out of memory\n");
543 return DMLERR_SYS_ERROR;
545 this_instance->Next_Entry = NULL;
546 this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
548 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
550 this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
551 this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
552 this_instance->CallBack=*pfnCallback;
553 this_instance->Txn_count=0;
554 this_instance->Unicode = TRUE;
555 this_instance->Win16 = FALSE;
556 this_instance->Node_list = NULL; /* node will be added later */
557 this_instance->Monitor_flags = afCmd & MF_MASK;
558 this_instance->ServiceNames = NULL;
560 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
562 this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
564 if ( ! this_instance->Client_only )
567 /* Check for other way of setting Client-only !! */
569 this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
570 ==CBF_FAIL_ALLSVRXACTIONS;
573 TRACE(ddeml,"instance created - checking validity \n");
575 if( *pidInst == 0 ) {
576 /* Initialisation of new Instance Identifier */
577 TRACE(ddeml,"new instance, callback %p flags %lX\n",pfnCallback,afCmd);
578 if ( DDE_Max_Assigned_Instance == 0 )
580 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
581 /* Need to set up Mutex in case it is not already present */
582 s_att->bInheritHandle = TRUE;
583 s_att->lpSecurityDescriptor = NULL;
584 s_att->nLength = sizeof(s_att);
585 handle_mutex = CreateMutexW(s_att,1,DDEHandleAccess);
586 if ( (err_no=GetLastError()) != 0 )
588 ERR(ddeml,"CreateMutex failed - handle list %li\n",err_no);
589 HeapFree(SystemHeap, 0, this_instance);
590 return DMLERR_SYS_ERROR;
594 WaitForSingleObject(handle_mutex,1000);
595 if ( (err_no=GetLastError()) != 0 )
597 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
599 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
600 return DMLERR_SYS_ERROR;
604 TRACE(ddeml,"Handle Mutex created/reserved\n");
605 if (DDE_Handle_Table_Base == NULL )
607 /* can't be another instance in this case, assign to the base pointer */
608 DDE_Handle_Table_Base= this_instance;
610 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
612 * ------------------------------- NOTE NOTE NOTE --------------------------
614 * the manual is not clear if this condition
615 * applies to the first call to DdeInitialize from an application, or the
616 * first call for a given callback !!!
619 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
620 TRACE(ddeml,"First application instance detected OK\n");
621 /* allocate new instance ID */
622 if ((err_no = IncrementInstanceId()) ) return err_no;
624 /* really need to chain the new one in to the latest here, but after checking conditions
625 * such as trying to start a conversation from an application trying to monitor */
626 reference_inst = DDE_Handle_Table_Base;
627 TRACE(ddeml,"Subsequent application instance - starting checks\n");
628 while ( reference_inst->Next_Entry != NULL )
631 * This set of tests will work if application uses same instance Id
632 * at application level once allocated - which is what manual implies
633 * should happen. If someone tries to be
634 * clever (lazy ?) it will fail to pick up that later calls are for
635 * the same application - should we trust them ?
637 if ( this_instance->Instance_id == reference_inst->Instance_id)
639 /* Check 1 - must be same Client-only state */
641 if ( this_instance->Client_only != reference_inst->Client_only)
643 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
644 return DMLERR_SYS_ERROR;
645 return DMLERR_DLL_USAGE;
648 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
650 if ( this_instance->Monitor != reference_inst->Monitor)
652 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
653 return DMLERR_SYS_ERROR;
654 return DMLERR_INVALIDPARAMETER;
657 /* Check 3 - must supply different callback address */
659 if ( this_instance->CallBack == reference_inst->CallBack)
661 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
662 return DMLERR_SYS_ERROR;
663 return DMLERR_DLL_USAGE;
666 reference_inst = reference_inst->Next_Entry;
668 /* All cleared, add to chain */
670 TRACE(ddeml,"Application Instance checks finished\n");
671 if ((err_no = IncrementInstanceId())) return err_no;
672 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0)) return DMLERR_SYS_ERROR;
673 reference_inst->Next_Entry = this_instance;
675 *pidInst = this_instance->Instance_id;
676 TRACE(ddeml,"New application instance processing finished OK\n");
678 /* Reinitialisation situation --- FIX */
679 TRACE(ddeml,"reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
680 WaitForSingleObject(handle_mutex,1000);
681 if ( (err_no=GetLastError()) != 0 )
684 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
686 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
687 HeapFree(SystemHeap, 0, this_instance);
688 return DMLERR_SYS_ERROR;
690 if (DDE_Handle_Table_Base == NULL )
692 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1)) return DMLERR_SYS_ERROR;
693 return DMLERR_DLL_USAGE;
695 HeapFree(SystemHeap, 0, this_instance); /* finished - release heap space used as work store */
696 /* can't reinitialise if we have initialised nothing !! */
697 reference_inst = DDE_Handle_Table_Base;
698 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
700 * MS allows initialisation without specifying a callback, should we allow addition of the
701 * callback by a later call to initialise ? - if so this lot will have to change
703 while ( reference_inst->Next_Entry != NULL )
705 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
707 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
709 if ( reference_inst->Client_only )
711 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
713 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
715 if ( ! ( afCmd & APPCMD_CLIENTONLY))
717 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
718 return DMLERR_SYS_ERROR;
719 return DMLERR_DLL_USAGE;
723 /* Check 2 - cannot change monitor modes */
725 if ( this_instance->Monitor != reference_inst->Monitor)
727 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
728 return DMLERR_SYS_ERROR;
729 return DMLERR_DLL_USAGE;
732 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
734 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
736 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
737 return DMLERR_SYS_ERROR;
738 return DMLERR_DLL_USAGE;
742 reference_inst = reference_inst->Next_Entry;
744 if ( reference_inst->Next_Entry == NULL )
746 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
748 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
750 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
751 return DMLERR_SYS_ERROR;
752 return DMLERR_INVALIDPARAMETER;
754 /* All checked - change relevant flags */
756 reference_inst->CBF_Flags = this_instance->CBF_Flags;
757 reference_inst->Client_only = this_instance->Client_only;
758 reference_inst->Monitor_flags = this_instance->Monitor_flags;
759 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
760 return DMLERR_SYS_ERROR;
763 return DMLERR_NO_ERROR;
767 /*****************************************************************
768 * DdeUninitialize16 (DDEML.3)
770 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
772 FIXME(ddeml," stub calling DdeUninitialize\n");
773 return (BOOL16)DdeUninitialize( idInst );
777 /*****************************************************************
778 * DdeUninitialize [USER32.119] Frees DDEML resources
781 * idInst [I] Instance identifier
788 BOOL WINAPI DdeUninitialize( DWORD idInst )
790 /* Stage one - check if we have a handle for this instance
792 SECURITY_ATTRIBUTES s_attrib;
795 if ( DDE_Max_Assigned_Instance == 0 )
797 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
800 WaitForSingleObject(handle_mutex,1000);
801 if ( (err_no=GetLastError()) != 0 )
803 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
805 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
806 return DMLERR_SYS_ERROR;
808 TRACE(ddeml,"Handle Mutex created/reserved\n");
809 /* First check instance
811 this_instance = Find_Instance_Entry(idInst);
812 if ( this_instance == NULL )
814 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return FALSE;
816 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
820 FIXME(ddeml, "(%ld): partial stub\n", idInst);
822 /* FIXME ++++++++++++++++++++++++++++++++++++++++++
823 * Needs to de-register all service names
826 /* Free the nodes that were not freed by this instance
827 * and remove the nodes from the list of HSZ nodes.
829 FreeAndRemoveHSZNodes( idInst );
831 /* OK now delete the instance handle itself */
833 if ( DDE_Handle_Table_Base == this_instance )
835 /* special case - the first/only entry
837 DDE_Handle_Table_Base = this_instance->Next_Entry;
842 reference_inst->Next_Entry = DDE_Handle_Table_Base;
843 while ( reference_inst->Next_Entry != this_instance )
845 reference_inst = this_instance->Next_Entry;
847 reference_inst->Next_Entry = this_instance->Next_Entry;
849 /* release the mutex and the heap entry
851 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE))
853 /* should record something here, but nothing left to hang it from !!
861 /*****************************************************************
862 * DdeConnectList16 [DDEML.4]
865 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
866 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
868 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
873 /******************************************************************************
874 * DdeConnectList [USER32.93] Establishes conversation with DDE servers
877 * idInst [I] Instance identifier
878 * hszService [I] Handle to service name string
879 * hszTopic [I] Handle to topic name string
880 * hConvList [I] Handle to conversation list
881 * pCC [I] Pointer to structure with context data
884 * Success: Handle to new conversation list
887 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
888 HCONVLIST hConvList, LPCONVCONTEXT pCC )
890 FIXME(ddeml, "(%ld,%ld,%ld,%ld,%p): stub\n", idInst, hszService, hszTopic,
896 /*****************************************************************
897 * DdeQueryNextServer16 [DDEML.5]
899 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
901 return DdeQueryNextServer(hConvList, hConvPrev);
905 /*****************************************************************
906 * DdeQueryNextServer [USER32.112]
908 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
910 FIXME(ddeml, "(%ld,%ld): stub\n",hConvList,hConvPrev);
914 /*****************************************************************
915 * DdeQueryStringA [USER32.113]
917 *****************************************************************
921 * Vn Date Author Comment
923 * 1.0 Dec 1998 Corel/Macadamian Initial version
924 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
927 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
930 CHAR pString[MAX_BUFFER_LEN];
933 "(%ld, 0x%lx, %p, %ld, %d): partial stub\n",
939 if ( DDE_Max_Assigned_Instance == 0 )
941 /* Nothing has been initialised - exit now ! */
942 /* needs something for DdeGetLAstError even if the manual doesn't say so */
945 WaitForSingleObject(handle_mutex,1000);
946 if ( (err_no=GetLastError()) != 0 )
948 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
950 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
951 /* needs something for DdeGetLAstError even if the manual doesn't say so */
954 TRACE(ddeml,"Handle Mutex created/reserved\n");
956 /* First check instance
958 reference_inst = Find_Instance_Entry(idInst);
959 if ( reference_inst == NULL )
961 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return FALSE;
963 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
968 if( iCodePage == CP_WINANSI )
970 /* If psz is null, we have to return only the length
976 cchMax = MAX_BUFFER_LEN;
979 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
981 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
983 TRACE(ddeml,"returning pointer\n");
987 /*****************************************************************
988 * DdeQueryStringW [USER32.114]
990 *****************************************************************
994 * Vn Date Author Comment
996 * 1.0 Dec 1998 Corel/Macadamian Initial version
1000 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
1003 WCHAR pString[MAX_BUFFER_LEN];
1007 "(%ld, 0x%lx, %p, %ld, %d): stub\n",
1014 if( iCodePage == CP_WINUNICODE )
1016 /* If psz is null, we have to return only the length
1022 cchMax = MAX_BUFFER_LEN;
1023 /* Note: According to documentation if the psz parameter
1024 * was NULL this API must return the length of the string in bytes.
1026 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
1028 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
1033 /*****************************************************************
1035 * DdeQueryString16 (DDEML.23)
1037 ******************************************************************
1041 * Vn Date Author Comment
1043 * 1.0 March 1999 K Matthews stub only
1046 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, int codepage)
1048 FIXME(ddeml,"(%ld, 0x%lx, %p, %ld, %d): stub \n",
1058 /*****************************************************************
1059 * DdeDisconnectList (DDEML.6)
1061 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
1063 return (BOOL16)DdeDisconnectList(hConvList);
1067 /******************************************************************************
1068 * DdeDisconnectList [USER32.98] Destroys list and terminates conversations
1074 BOOL WINAPI DdeDisconnectList(
1075 HCONVLIST hConvList) /* [in] Handle to conversation list */
1077 FIXME(ddeml, "(%ld): stub\n", hConvList);
1082 /*****************************************************************
1083 * DdeConnect16 (DDEML.7)
1085 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
1086 LPCONVCONTEXT16 pCC )
1088 FIXME( ddeml, "empty stub\n" );
1093 /*****************************************************************
1094 * DdeConnect (USER32.92)
1096 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
1099 FIXME(ddeml, "(0x%lx,%ld,%ld,%p): stub\n",idInst,hszService,hszTopic,
1105 /*****************************************************************
1106 * DdeDisconnect16 (DDEML.8)
1108 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
1110 return (BOOL16)DdeDisconnect( hConv );
1113 /*****************************************************************
1114 * DdeSetUserHandle16 (DDEML.10)
1116 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
1118 FIXME( ddeml, "(%ld,%ld,%ld): stub\n",hConv,id, hUser );
1122 /*****************************************************************
1123 * DdeCreateDataHandle16 (DDEML.14)
1125 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
1126 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
1129 return DdeCreateDataHandle(idInst,
1138 /*****************************************************************
1139 * DdeCreateDataHandle (USER32.94)
1141 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
1142 DWORD cbOff, HSZ hszItem, UINT wFmt,
1146 "(%ld,%p,%ld,%ld,0x%lx,%d,%d): stub\n",
1158 /*****************************************************************
1159 * DdeDisconnect (USER32.97)
1161 BOOL WINAPI DdeDisconnect( HCONV hConv )
1163 FIXME( ddeml, "empty stub\n" );
1168 /*****************************************************************
1169 * DdeReconnect (DDEML.37) (USER32.115)
1171 HCONV WINAPI DdeReconnect( HCONV hConv )
1173 FIXME( ddeml, "empty stub\n" );
1178 /*****************************************************************
1179 * DdeCreateStringHandle16 (DDEML.21)
1181 *****************************************************************
1185 * Vn Date Author Comment
1187 * 1.0 ? ? basic stub
1188 * 1.1 June 1999 Keith Matthews amended onward call to supply default
1189 * code page if none supplied by caller
1191 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1195 return DdeCreateStringHandleA( idInst, str, codepage );
1197 TRACE(ddeml,"Default codepage supplied\n");
1198 return DdeCreateStringHandleA( idInst, str, CP_WINANSI);
1203 /*****************************************************************
1204 * DdeCreateStringHandleA [USER32.95]
1207 * Success: String handle
1210 *****************************************************************
1214 * Vn Date Author Comment
1216 * 1.0 Dec 1998 Corel/Macadamian Initial version
1217 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1220 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1223 TRACE(ddeml, "(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1226 if ( DDE_Max_Assigned_Instance == 0 )
1228 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1231 WaitForSingleObject(handle_mutex,1000);
1232 if ( (err_no=GetLastError()) != 0 )
1234 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1236 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1237 return DMLERR_SYS_ERROR;
1239 TRACE(ddeml,"Handle Mutex created/reserved\n");
1241 /* First check instance
1243 reference_inst = Find_Instance_Entry(idInst);
1244 if ( reference_inst == NULL )
1246 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return 0;
1248 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1253 if (codepage==CP_WINANSI)
1255 hsz = GlobalAddAtomA (psz);
1256 /* Save the handle so we know to clean it when
1257 * uninitialize is called.
1259 TRACE(ddeml,"added atom %s with HSZ 0x%lx, \n",debugstr_a(psz),hsz);
1260 InsertHSZNode( hsz );
1261 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE))
1263 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1266 TRACE(ddeml,"Returning pointer\n");
1269 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1271 TRACE(ddeml,"Returning error\n");
1276 /******************************************************************************
1277 * DdeCreateStringHandleW [USER32.96] Creates handle to identify string
1280 * Success: String handle
1283 *****************************************************************
1287 * Vn Date Author Comment
1289 * 1.0 Dec 1998 Corel/Macadamian Initial version
1290 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1293 HSZ WINAPI DdeCreateStringHandleW(
1294 DWORD idInst, /* [in] Instance identifier */
1295 LPCWSTR psz, /* [in] Pointer to string */
1296 INT codepage) /* [in] Code page identifier */
1300 TRACE(ddeml, "(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1303 if ( DDE_Max_Assigned_Instance == 0 )
1305 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1308 WaitForSingleObject(handle_mutex,1000);
1309 if ( (err_no=GetLastError()) != 0 )
1311 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1313 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1314 return DMLERR_SYS_ERROR;
1316 TRACE(ddeml,"CreateString - Handle Mutex created/reserved\n");
1318 /* First check instance
1320 reference_inst = Find_Instance_Entry(idInst);
1321 if ( reference_inst == NULL )
1323 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return 0;
1325 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1330 FIXME(ddeml, "(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1332 if (codepage==CP_WINUNICODE)
1334 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1337 hsz = GlobalAddAtomW (psz);
1338 /* Save the handle so we know to clean it when
1339 * uninitialize is called.
1341 InsertHSZNode( hsz );
1342 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE))
1344 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1347 TRACE(ddeml,"Returning pointer\n");
1350 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1352 TRACE(ddeml,"Returning error\n");
1357 /*****************************************************************
1358 * DdeFreeStringHandle16 (DDEML.22)
1360 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1362 FIXME(ddeml,"idInst %ld hsz 0x%lx\n",idInst,hsz);
1363 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1367 /*****************************************************************
1368 * DdeFreeStringHandle (USER32.101)
1369 * RETURNS: success: nonzero
1372 *****************************************************************
1376 * Vn Date Author Comment
1378 * 1.0 Dec 1998 Corel/Macadamian Initial version
1379 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1382 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1384 TRACE(ddeml, "(%ld,%ld): \n",idInst,hsz);
1385 if ( DDE_Max_Assigned_Instance == 0 )
1387 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1390 if ( ( prev_err = GetLastError()) != 0 )
1392 /* something earlier failed !! */
1393 ERR(ddeml,"Error %li before WaitForSingleObject - trying to continue\n",prev_err);
1395 WaitForSingleObject(handle_mutex,1000);
1396 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
1398 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1400 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1401 return DMLERR_SYS_ERROR;
1403 TRACE(ddeml,"Handle Mutex created/reserved\n");
1405 /* First check instance
1407 reference_inst = Find_Instance_Entry(idInst);
1408 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1410 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return TRUE;
1411 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1416 /* Remove the node associated with this HSZ.
1418 RemoveHSZNode( hsz );
1419 /* Free the string associated with this HSZ.
1421 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1422 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1426 /*****************************************************************
1427 * DdeFreeDataHandle16 (DDEML.19)
1429 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1431 return (BOOL)DdeFreeDataHandle( hData );
1435 /*****************************************************************
1436 * DdeFreeDataHandle (USER32.100)
1438 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1440 FIXME( ddeml, "empty stub\n" );
1447 /*****************************************************************
1448 * DdeKeepStringHandle16 (DDEML.24)
1450 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1452 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1456 /*****************************************************************
1457 * DdeKeepStringHandle (USER32.108)
1459 * RETURNS: success: nonzero
1462 *****************************************************************
1466 * Vn Date Author Comment
1469 * 1.1 Jun 1999 Keith Matthews First cut implementation
1472 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1475 TRACE(ddeml, "(%ld,%ld): \n",idInst,hsz);
1476 if ( DDE_Max_Assigned_Instance == 0 )
1478 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1481 if ( ( prev_err = GetLastError()) != 0 )
1483 /* something earlier failed !! */
1484 ERR(ddeml,"Error %li before WaitForSingleObject - trying to continue\n",prev_err);
1486 WaitForSingleObject(handle_mutex,1000);
1487 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
1489 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1491 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1494 TRACE(ddeml,"Handle Mutex created/reserved\n");
1496 /* First check instance
1498 reference_inst = Find_Instance_Entry(idInst);
1499 if ( (reference_inst == NULL) || (reference_inst->Node_list == NULL))
1501 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return FALSE;
1502 /* Nothing has been initialised - exit now ! can return FALSE since effect is the same */
1506 DdeReserveAtom(reference_inst,hsz);
1507 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1512 /*****************************************************************
1513 * DdeClientTransaction16 (DDEML.11)
1515 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1516 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1517 UINT16 wType, DWORD dwTimeout,
1520 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1521 wFmt, wType, dwTimeout, pdwResult );
1525 /*****************************************************************
1526 * DdeClientTransaction (USER32.90)
1528 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1529 HCONV hConv, HSZ hszItem, UINT wFmt,
1530 UINT wType, DWORD dwTimeout,
1533 FIXME( ddeml, "empty stub\n" );
1537 /*****************************************************************
1539 * DdeAbandonTransaction16 (DDEML.12)
1542 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1543 DWORD idTransaction )
1545 FIXME( ddeml, "empty stub\n" );
1550 /*****************************************************************
1552 * DdeAbandonTransaction (USER32.87)
1554 ******************************************************************
1558 * Vn Date Author Comment
1560 * 1.0 March 1999 K Matthews stub only
1562 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1563 DWORD idTransaction )
1565 FIXME( ddeml, "empty stub\n" );
1569 /*****************************************************************
1570 * DdePostAdvise16 [DDEML.13]
1572 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1574 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1578 /******************************************************************************
1579 * DdePostAdvise [USER32.110] Send transaction to DDE callback function.
1585 BOOL WINAPI DdePostAdvise(
1586 DWORD idInst, /* [in] Instance identifier */
1587 HSZ hszTopic, /* [in] Handle to topic name string */
1588 HSZ hszItem) /* [in] Handle to item name string */
1590 FIXME(ddeml, "(%ld,%ld,%ld): stub\n",idInst,hszTopic,hszItem);
1595 /*****************************************************************
1596 * DdeAddData16 (DDEML.15)
1598 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1601 FIXME( ddeml, "empty stub\n" );
1605 /*****************************************************************
1607 * DdeAddData (USER32.89)
1609 ******************************************************************
1613 * Vn Date Author Comment
1615 * 1.0 March 1999 K Matthews stub only
1617 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1620 FIXME( ddeml, "empty stub\n" );
1625 /*****************************************************************
1627 * DdeImpersonateClient (USER32.105)
1629 ******************************************************************
1633 * Vn Date Author Comment
1635 * 1.0 March 1999 K Matthews stub only
1638 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1640 FIXME( ddeml, "empty stub\n" );
1645 /*****************************************************************
1647 * DdeSetQualityOfService (USER32.116)
1649 ******************************************************************
1653 * Vn Date Author Comment
1655 * 1.0 March 1999 K Matthews stub only
1658 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1659 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1661 FIXME( ddeml, "empty stub\n" );
1665 /*****************************************************************
1667 * DdeSetUserHandle (USER32.117)
1669 ******************************************************************
1673 * Vn Date Author Comment
1675 * 1.0 March 1999 K Matthews stub only
1678 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1680 FIXME( ddeml, "empty stub\n" );
1684 /******************************************************************************
1685 * DdeGetData [USER32.102] Copies data from DDE object ot local buffer
1688 * Size of memory object associated with handle
1690 DWORD WINAPI DdeGetData(
1691 HDDEDATA hData, /* [in] Handle to DDE object */
1692 LPBYTE pDst, /* [in] Pointer to destination buffer */
1693 DWORD cbMax, /* [in] Amount of data to copy */
1694 DWORD cbOff) /* [in] Offset to beginning of data */
1696 FIXME(ddeml, "(%ld,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1701 /*****************************************************************
1702 * DdeGetData16 [DDEML.16]
1704 DWORD WINAPI DdeGetData16(
1710 return DdeGetData(hData, pDst, cbMax, cbOff);
1714 /*****************************************************************
1715 * DdeAccessData16 (DDEML.17)
1717 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1719 return DdeAccessData(hData, pcbDataSize);
1722 /*****************************************************************
1723 * DdeAccessData (USER32.88)
1725 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1727 FIXME( ddeml, "(%ld,%p): stub\n", hData, pcbDataSize);
1731 /*****************************************************************
1732 * DdeUnaccessData16 (DDEML.18)
1734 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1736 return DdeUnaccessData(hData);
1739 /*****************************************************************
1740 * DdeUnaccessData (USER32.118)
1742 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1744 FIXME( ddeml, "(0x%lx): stub\n", hData);
1749 /*****************************************************************
1750 * DdeEnableCallback16 (DDEML.26)
1752 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1754 return DdeEnableCallback(idInst, hConv, wCmd);
1757 /*****************************************************************
1758 * DdeEnableCallback (USER32.99)
1760 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1762 FIXME( ddeml, "(%ld, 0x%lx, %d) stub\n", idInst, hConv, wCmd);
1767 /*****************************************************************
1768 * DdeNameService16 (DDEML.27)
1770 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1773 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1777 /******************************************************************************
1778 * DdeNameService [USER32.109] {Un}registers service name of DDE server
1781 * idInst [I] Instance identifier
1782 * hsz1 [I] Handle to service name string
1784 * afCmd [I] Service name flags
1790 *****************************************************************
1794 * Vn Date Author Comment
1797 * 1.1 Apr 1999 Keith Matthews Added trap for non-existent instance (uninitialised instance 0
1798 * used by some MS programs for unfathomable reasons)
1799 * 1.2 May 1999 Keith Matthews Added parameter validation and basic service name handling.
1800 * Still needs callback parts
1803 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1806 UINT Cmd_flags = afCmd;
1807 ServiceNode* this_service, *reference_service ;
1808 CHAR SNameBuffer[MAX_BUFFER_LEN];
1810 this_service = NULL;
1811 FIXME(ddeml, "(%ld,%ld,%ld,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1812 if ( DDE_Max_Assigned_Instance == 0 )
1814 /* Nothing has been initialised - exit now !
1815 * needs something for DdeGetLastError */
1818 WaitForSingleObject(handle_mutex,1000);
1819 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
1821 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1823 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1824 return DMLERR_SYS_ERROR;
1826 TRACE(ddeml,"Handle Mutex created/reserved\n");
1828 /* First check instance
1830 reference_inst = Find_Instance_Entry(idInst);
1831 this_instance = reference_inst;
1832 if (reference_inst == NULL)
1834 TRACE(ddeml,"Instance not found as initialised\n");
1835 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return TRUE;
1836 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1843 /* Illegal, reserved parameter
1845 reference_inst->Last_Error = DMLERR_INVALIDPARAMETER;
1846 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1847 FIXME(ddeml,"Reserved parameter no-zero !!\n");
1853 * General unregister situation
1855 if ( afCmd != DNS_UNREGISTER )
1857 /* don't know if we should check this but it makes sense
1858 * why supply REGISTER or filter flags if de-registering all
1860 TRACE(ddeml,"General unregister unexpected flags\n");
1861 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1862 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1865 /* Loop to find all registered service and de-register them
1867 if ( reference_inst->ServiceNames == NULL )
1869 /* None to unregister !!
1871 TRACE(ddeml,"General de-register - nothing registered\n");
1872 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1873 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1877 this_service = reference_inst->ServiceNames;
1878 while ( this_service->next != NULL)
1880 reference_service = this_service;
1881 this_service = this_service->next;
1882 DdeReleaseAtom(reference_inst,reference_service->hsz);
1883 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space used as work store */
1885 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space used as work store */
1886 TRACE(ddeml,"General de-register - finished\n");
1888 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1891 TRACE(ddeml,"Specific name action detected\n");
1892 reference_service = Find_Service_Name(hsz1,reference_inst);
1893 if (( Cmd_flags && DNS_REGISTER ) == DNS_REGISTER )
1895 /* Register new service name
1898 rcode=GlobalGetAtomNameA(hsz1,SNameBuffer,MAX_ATOM_LEN);
1899 Cmd_flags = Cmd_flags ^ DNS_REGISTER;
1900 this_service= (ServiceNode*)HeapAlloc( SystemHeap, 0, sizeof(ServiceNode) );
1901 this_service->next = NULL;
1902 this_service->hsz = hsz1;
1903 this_service->FilterOn = TRUE;
1904 if ( reference_inst->ServiceNames == NULL )
1906 /* easy one - nothing else there
1908 TRACE(ddeml,"Adding 1st service name\n");
1909 reference_inst->ServiceNames = this_service;
1910 GlobalAddAtomA(SNameBuffer);
1913 /* more difficult - may have also been registered
1915 if (reference_service != NULL )
1917 /* Service name already registered !!
1920 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space used as work store */
1921 FIXME(ddeml,"Trying to register already registered service !!\n");
1924 /* Add this one into the chain
1926 TRACE(ddeml,"Adding subsequent service name\n");
1927 this_service->next = reference_inst->ServiceNames;
1928 reference_inst->ServiceNames = this_service;
1929 GlobalAddAtomA(SNameBuffer);
1933 if ( (Cmd_flags && DNS_UNREGISTER ) == DNS_UNREGISTER )
1935 /* De-register service name
1937 Cmd_flags = Cmd_flags ^ DNS_UNREGISTER;
1938 if ( reference_inst->ServiceNames == NULL )
1940 /* easy one - already done
1944 /* more difficult - must hook out of sequence
1946 this_instance = reference_inst;
1947 if (this_service == NULL )
1949 /* Service name not registered !!
1952 FIXME(ddeml,"Trying to de-register unregistered service !!\n");
1955 /* Delete this one from the chain
1957 if ( reference_inst->ServiceNames == this_service )
1959 /* special case - the first/only entry
1961 reference_inst->ServiceNames = this_service->next;
1966 reference_service->next= reference_inst->ServiceNames;
1967 while ( reference_service->next!= this_service )
1969 reference_service = reference_service->next;
1971 reference_service->next= this_service->next;
1973 DdeReleaseAtom(reference_inst,this_service->hsz);
1974 HeapFree(SystemHeap, 0, this_service); /* finished - release heap space */
1978 if ( ( Cmd_flags && DNS_FILTEROFF ) != DNS_FILTEROFF )
1980 /* Set filter flags on to hold notifications of connection
1982 * test coded this way as this is the default setting
1984 Cmd_flags = Cmd_flags ^ DNS_FILTERON;
1985 if ( ( reference_inst->ServiceNames == NULL ) || ( this_service == NULL) )
1987 /* trying to filter where no service names !!
1989 reference_inst->Last_Error = DMLERR_DLL_USAGE;
1990 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
1994 this_service->FilterOn = TRUE;
1997 if ( ( Cmd_flags && DNS_FILTEROFF ) == DNS_FILTEROFF )
1999 /* Set filter flags on to hold notifications of connection
2001 Cmd_flags = Cmd_flags ^ DNS_FILTEROFF;
2002 if ( ( reference_inst->ServiceNames == NULL ) || ( this_service == NULL) )
2004 /* trying to filter where no service names !!
2006 reference_inst->Last_Error = DMLERR_DLL_USAGE;
2007 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
2011 this_service->FilterOn = FALSE;
2014 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
2019 /*****************************************************************
2020 * DdeGetLastError16 (DDEML.20)
2022 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
2024 return (UINT16)DdeGetLastError( idInst );
2028 /******************************************************************************
2029 * DdeGetLastError [USER32.103] Gets most recent error code
2032 * idInst [I] Instance identifier
2037 *****************************************************************
2041 * Vn Date Author Comment
2044 * 1.1 Apr 1999 Keith Matthews Added response for non-existent instance (uninitialised instance 0
2045 * used by some MS programs for unfathomable reasons)
2046 * 1.2 May 1999 Keith Matthews Added interrogation of Last_Error for instance handle where found.
2049 UINT WINAPI DdeGetLastError( DWORD idInst )
2052 FIXME(ddeml, "(%ld): stub\n",idInst);
2053 if ( DDE_Max_Assigned_Instance == 0 )
2055 /* Nothing has been initialised - exit now ! */
2056 return DMLERR_DLL_NOT_INITIALIZED;
2058 if ( ( prev_err = GetLastError()) != 0 )
2060 /* something earlier failed !! */
2061 ERR(ddeml,"Error %li before WaitForSingleObject - trying to continue\n",prev_err);
2063 WaitForSingleObject(handle_mutex,1000);
2064 if ( ((err_no=GetLastError()) != 0 ) && (err_no != prev_err ))
2066 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
2068 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
2069 return DMLERR_SYS_ERROR;
2071 TRACE(ddeml,"Handle Mutex created/reserved\n");
2073 /* First check instance
2075 reference_inst = Find_Instance_Entry(idInst);
2076 if (reference_inst == NULL)
2078 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return TRUE;
2079 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
2080 return DMLERR_DLL_NOT_INITIALIZED;
2083 error_code = this_instance->Last_Error;
2084 this_instance->Last_Error = 0;
2085 Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE);
2090 /*****************************************************************
2091 * DdeCmpStringHandles16 (DDEML.36)
2093 int WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
2095 return DdeCmpStringHandles(hsz1, hsz2);
2098 /*****************************************************************
2099 * DdeCmpStringHandles (USER32.91)
2101 * Compares the value of two string handles. This comparison is
2102 * not case sensitive.
2105 * -1 The value of hsz1 is zero or less than hsz2
2106 * 0 The values of hsz 1 and 2 are the same or both zero.
2107 * 1 The value of hsz2 is zero of less than hsz1
2109 int WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
2111 CHAR psz1[MAX_BUFFER_LEN];
2112 CHAR psz2[MAX_BUFFER_LEN];
2116 TRACE( ddeml, "handle 1, handle 2\n" );
2118 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
2119 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
2120 /* Make sure we found both strings.
2122 if( ret1 == 0 && ret2 == 0 )
2124 /* If both are not found, return both "zero strings".
2128 else if( ret1 == 0 )
2130 /* If hsz1 is a not found, return hsz1 is "zero string".
2134 else if( ret2 == 0 )
2136 /* If hsz2 is a not found, return hsz2 is "zero string".
2142 /* Compare the two strings we got ( case insensitive ).
2144 ret = strcasecmp( psz1, psz2 );
2145 /* Since strcmp returns any number smaller than
2146 * 0 when the first string is found to be less than
2147 * the second one we must make sure we are returning
2148 * the proper values.
2163 /*****************************************************************
2164 * PackDDElParam (USER32.414)
2170 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
2172 FIXME(ddeml, "stub.\n");
2177 /*****************************************************************
2178 * UnpackDDElParam (USER32.562)
2184 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
2185 UINT *uiLo, UINT *uiHi)
2187 FIXME(ddeml, "stub.\n");
2192 /*****************************************************************
2193 * FreeDDElParam (USER32.204)
2199 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
2201 FIXME(ddeml, "stub.\n");
2205 /*****************************************************************
2206 * ReuseDDElParam (USER32.446)
2209 UINT WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
2210 UINT uiLi, UINT uiHi)
2212 FIXME(ddeml, "stub.\n");
2216 /******************************************************************
2217 * DdeQueryConvInfo16 (DDEML.9)
2220 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
2222 FIXME(ddeml,"stub.\n");
2227 /******************************************************************
2228 * DdeQueryConvInfo (USER32.111)
2231 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)
2233 FIXME(ddeml,"stub.\n");