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"
22 /* Has defined in atom.c file.
24 #define MAX_ATOM_LEN 255
26 /* Maximum buffer size ( including the '\0' ).
28 #define MAX_BUFFER_LEN (MAX_ATOM_LEN + 1)
32 LPVOID lpSecurityDescriptor;
34 } SECURITY_ATTRIBUTES; */
36 /* This is a simple list to keep track of the strings created
37 * by DdeCreateStringHandle. The list is used to free
38 * the strings whenever DdeUninitialize is called.
39 * This mechanism is not complete and does not handle multiple instances.
40 * Most of the DDE API use a DWORD parameter indicating which instance
41 * of a given program is calling them. The API are supposed to
42 * associate the data to the instance that created it.
44 typedef struct tagHSZNode HSZNode;
52 typedef struct DDE_HANDLE_ENTRY {
53 BOOL16 Monitor; /* have these two as full Booleans cos they'll be tested frequently */
54 BOOL16 Client_only; /* bit wasteful of space but it will be faster */
55 BOOL16 Unicode; /* Flag to indicate Win32 API used to initialise */
56 BOOL16 Win16; /* flag to indicate Win16 API used to initialize */
57 DWORD Instance_id; /* needed to track monitor usage */
58 struct DDE_HANDLE_ENTRY *Next_Entry;
63 UINT Txn_count; /* count transactions open to simplify closure */
67 static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
68 static DWORD DDE_Max_Assigned_Instance = 0; /* OK for present, may have to worry about wrap-around later */
69 static const char inst_string[]= "DDEMaxInstance";
70 static LPCWSTR DDEInstanceAccess = (LPCWSTR)&inst_string;
71 static const char handle_string[] = "DDEHandleAccess";
72 static LPCWSTR DDEHandleAccess = (LPCWSTR)&handle_string;
73 static HANDLE inst_count_mutex = 0;
74 static HANDLE handle_mutex = 0;
75 DDE_HANDLE_ENTRY *this_instance;
76 SECURITY_ATTRIBUTES *s_att= NULL;
78 DDE_HANDLE_ENTRY *reference_inst;
84 /******************************************************************************
85 * RemoveHSZNodes (INTERNAL)
87 * Remove a node from the list of HSZ nodes.
89 ******************************************************************************
93 * Vn Date Author Comment
95 * 1.0 Dec 1998 Corel/Macadamian Initial version
96 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
99 static void RemoveHSZNode( HSZ hsz )
101 HSZNode* pPrev = NULL;
102 HSZNode* pCurrent = NULL;
104 /* Set the current node at the start of the list.
106 pCurrent = reference_inst->Node_list;
107 /* While we have more nodes.
109 while( pCurrent != NULL )
111 /* If we found the node we were looking for.
113 if( pCurrent->hsz == hsz )
117 /* If the first node in the list is to to be removed.
118 * Set the global list pointer to the next node.
120 if( pCurrent == reference_inst->Node_list )
122 reference_inst->Node_list = pCurrent->next;
124 /* Just fix the pointers has to skip the current
125 * node so we can delete it.
129 pPrev->next = pCurrent->next;
131 /* Destroy this node.
136 /* Save the previous node pointer.
139 /* Move on to the next node.
141 pCurrent = pCurrent->next;
145 /******************************************************************************
146 * FreeAndRemoveHSZNodes (INTERNAL)
148 * Frees up all the strings still allocated in the list and
149 * remove all the nodes from the list of HSZ nodes.
151 ******************************************************************************
155 * Vn Date Author Comment
157 * 1.0 Dec 1998 Corel/Macadamian Initial version
158 * 1.1 Mar 1999 Keith Matthews Added multiple instance handling
161 static void FreeAndRemoveHSZNodes( DWORD idInst )
163 /* Free any strings created in this instance.
165 while( reference_inst->Node_list != NULL )
167 DdeFreeStringHandle( idInst, reference_inst->Node_list->hsz );
171 /******************************************************************************
172 * InsertHSZNode (INTERNAL)
174 * Insert a node to the head of the list.
176 ******************************************************************************
180 * Vn Date Author Comment
182 * 1.0 Dec 1998 Corel/Macadamian Initial version
183 * 1.1 Mar 1999 Keith Matthews Added instance handling
186 static void InsertHSZNode( HSZ hsz )
190 HSZNode* pNew = NULL;
191 /* Create a new node for this HSZ.
193 pNew = (HSZNode*) malloc( sizeof( HSZNode ) );
196 /* Set the handle value.
199 /* Attach the node to the head of the list. i.e most recently added is first
201 pNew->next = reference_inst->Node_list;
202 /* The new node is now at the head of the list
203 * so set the global list pointer to it.
205 reference_inst->Node_list = pNew;
206 TRACE(ddeml,"HSZ node list entry added\n");
211 /*****************************************************************************
212 * Find_Instance_Entry
214 * generic routine to return a pointer to the relevant DDE_HANDLE_ENTRY
215 * for an instance Id, or NULL if the entry does not exist
217 * ASSUMES the mutex protecting the handle entry list is reserved before calling
219 ******************************************************************************
223 * Vn Date Author Comment
225 * 1.0 March 1999 Keith Matthews 1st implementation
227 DDE_HANDLE_ENTRY *Find_Instance_Entry (DWORD InstId)
229 reference_inst = DDE_Handle_Table_Base;
230 while ( reference_inst != NULL )
232 if ( reference_inst->Instance_id == InstId )
234 TRACE(ddeml,"Instance entry found\n");
235 return reference_inst;
237 reference_inst = reference_inst->Next_Entry;
239 TRACE(ddeml,"Instance entry missing\n");
243 /******************************************************************************
244 * Release_reserved_mutex
246 * generic routine to release a reserved mutex
249 ******************************************************************************
253 * Vn Date Author Comment
255 * 1.0 Jan 1999 Keith Matthews Initial version
256 * 1.1 Mar 1999 Keith Matthews Corrected Heap handling. Corrected re-initialisation handling
259 DWORD Release_reserved_mutex (HANDLE mutex, LPTSTR mutex_name, BOOL release_handle_m, BOOL release_this_i )
262 if ( (err_no=GetLastError()) != 0 )
264 ERR(ddeml,"ReleaseMutex failed - %s mutex %li\n",mutex_name,err_no);
265 HeapFree(SystemHeap, 0, this_instance);
266 if ( release_handle_m )
268 ReleaseMutex(handle_mutex);
270 return DMLERR_SYS_ERROR;
272 if ( release_this_i )
274 HeapFree(SystemHeap, 0, this_instance);
276 return DMLERR_NO_ERROR;
279 /******************************************************************************
280 * IncrementInstanceId
282 * generic routine to increment the max instance Id and allocate a new application instance
284 ******************************************************************************
288 * Vn Date Author Comment
290 * 1.0 Jan 1999 Keith Matthews Initial version
293 DWORD IncrementInstanceId()
295 SECURITY_ATTRIBUTES s_attrib;
296 /* Need to set up Mutex in case it is not already present */
297 /* increment handle count & get value */
298 if ( !inst_count_mutex )
300 s_attrib.bInheritHandle = TRUE;
301 s_attrib.lpSecurityDescriptor = NULL;
302 s_attrib.nLength = sizeof(s_attrib);
303 inst_count_mutex = CreateMutexW(&s_attrib,1,DDEInstanceAccess); /* 1st time through */
305 WaitForSingleObject(inst_count_mutex,1000); /* subsequent calls */
306 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
308 if ( (err_no=GetLastError()) != 0 )
310 ERR(ddeml,"CreateMutex failed - inst_count %li\n",err_no);
311 err_no=Release_reserved_mutex (handle_mutex,"handle_mutex",0,1);
312 return DMLERR_SYS_ERROR;
314 DDE_Max_Assigned_Instance++;
315 this_instance->Instance_id = DDE_Max_Assigned_Instance;
316 TRACE(ddeml,"New instance id %ld allocated\n",DDE_Max_Assigned_Instance);
317 if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0)) return DMLERR_SYS_ERROR;
318 return DMLERR_NO_ERROR;
321 /******************************************************************************
322 * DdeInitialize16 (DDEML.2)
324 UINT16 WINAPI DdeInitialize16( LPDWORD pidInst, PFNCALLBACK16 pfnCallback,
325 DWORD afCmd, DWORD ulRes)
327 TRACE(ddeml,"DdeInitialize16 called - calling DdeInitializeA\n");
328 return (UINT16)DdeInitializeA(pidInst,(PFNCALLBACK)pfnCallback,
333 /******************************************************************************
334 * DdeInitializeA (USER32.106)
336 UINT WINAPI DdeInitializeA( LPDWORD pidInst, PFNCALLBACK pfnCallback,
337 DWORD afCmd, DWORD ulRes )
339 TRACE(ddeml,"DdeInitializeA called - calling DdeInitializeW\n");
340 return DdeInitializeW(pidInst,pfnCallback,afCmd,ulRes);
344 /******************************************************************************
345 * DdeInitializeW [USER32.107]
346 * Registers an application with the DDEML
349 * pidInst [I] Pointer to instance identifier
350 * pfnCallback [I] Pointer to callback function
351 * afCmd [I] Set of command and filter flags
355 * Success: DMLERR_NO_ERROR
356 * Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
358 ******************************************************************************
362 * Vn Date Author Comment
364 * 1.0 Pre 1998 Alexandre/Len Initial Stub
365 * 1.1 Jan 1999 Keith Matthews Initial (near-)complete version
366 * 1.2 Mar 1999 Keith Matthews Corrected Heap handling, CreateMutex failure handling
369 UINT WINAPI DdeInitializeW( LPDWORD pidInst, PFNCALLBACK pfnCallback,
370 DWORD afCmd, DWORD ulRes )
373 /* probably not really capable of handling mutliple processes, but should handle
374 * multiple instances within one process */
376 SECURITY_ATTRIBUTES s_attrib;
381 ERR(ddeml, "Reserved value not zero? What does this mean?\n");
382 FIXME(ddeml, "(%p,%p,0x%lx,%ld): stub\n", pidInst, pfnCallback,
384 /* trap this and no more until we know more */
385 return DMLERR_NO_ERROR;
389 /* this one may be wrong - MS dll seems to accept the condition,
390 leave this until we find out more !! */
393 /* can't set up the instance with nothing to act as a callback */
394 TRACE(ddeml,"No callback provided\n");
395 return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
398 /* grab enough heap for one control struct - not really necessary for re-initialise
399 * but allows us to use same validation routines */
400 this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( SystemHeap, 0, sizeof(DDE_HANDLE_ENTRY) );
401 if ( this_instance == NULL )
403 /* catastrophe !! warn user & abort */
404 ERR (ddeml, "Instance create failed - out of memory\n");
405 return DMLERR_SYS_ERROR;
407 this_instance->Next_Entry = NULL;
408 this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
410 /* messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here */
412 this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
413 this_instance->Instance_id = *pidInst; /* May need to add calling proc Id */
414 this_instance->CallBack=*pfnCallback;
415 this_instance->Txn_count=0;
416 this_instance->Unicode = TRUE;
417 this_instance->Win16 = FALSE;
418 this_instance->Node_list = NULL; /* node will be added later */
419 this_instance->Monitor_flags = afCmd & MF_MASK;
421 /* isolate CBF flags in one go, expect this will go the way of all attempts to be clever !! */
423 this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
425 if ( ! this_instance->Client_only )
428 /* Check for other way of setting Client-only !! */
430 this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
431 ==CBF_FAIL_ALLSVRXACTIONS;
434 TRACE(ddeml,"instance created - checking validity \n");
436 if( *pidInst == 0 ) {
437 /* Initialisation of new Instance Identifier */
438 TRACE(ddeml,"new instance, callback %p flags %lX\n",pfnCallback,afCmd);
439 if ( DDE_Max_Assigned_Instance == 0 )
441 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
442 /* Need to set up Mutex in case it is not already present */
443 s_att->bInheritHandle = TRUE;
444 s_att->lpSecurityDescriptor = NULL;
445 s_att->nLength = sizeof(s_att);
446 handle_mutex = CreateMutexW(s_att,1,DDEHandleAccess);
447 if ( (err_no=GetLastError()) != 0 )
449 ERR(ddeml,"CreateMutex failed - handle list %li\n",err_no);
450 HeapFree(SystemHeap, 0, this_instance);
451 return DMLERR_SYS_ERROR;
455 WaitForSingleObject(handle_mutex,1000);
456 if ( (err_no=GetLastError()) != 0 )
458 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
460 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
461 return DMLERR_SYS_ERROR;
465 TRACE(ddeml,"Handle Mutex created/reserved\n");
466 if (DDE_Handle_Table_Base == NULL )
468 /* can't be another instance in this case, assign to the base pointer */
469 DDE_Handle_Table_Base= this_instance;
471 /* since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
473 * ------------------------------- NOTE NOTE NOTE --------------------------
475 * the manual is not clear if this condition
476 * applies to the first call to DdeInitialize from an application, or the
477 * first call for a given callback !!!
480 this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
481 TRACE(ddeml,"First application instance detected OK\n");
482 /* allocate new instance ID */
483 if ((err_no = IncrementInstanceId()) ) return err_no;
485 /* really need to chain the new one in to the latest here, but after checking conditions
486 * such as trying to start a conversation from an application trying to monitor */
487 reference_inst = DDE_Handle_Table_Base;
488 TRACE(ddeml,"Subsequent application instance - starting checks\n");
489 while ( reference_inst->Next_Entry != NULL )
492 * This set of tests will work if application uses same instance Id
493 * at application level once allocated - which is what manual implies
494 * should happen. If someone tries to be
495 * clever (lazy ?) it will fail to pick up that later calls are for
496 * the same application - should we trust them ?
498 if ( this_instance->Instance_id == reference_inst->Instance_id)
500 /* Check 1 - must be same Client-only state */
502 if ( this_instance->Client_only != reference_inst->Client_only)
504 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
505 return DMLERR_SYS_ERROR;
506 return DMLERR_DLL_USAGE;
509 /* Check 2 - cannot use 'Monitor' with any non-monitor modes */
511 if ( this_instance->Monitor != reference_inst->Monitor)
513 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
514 return DMLERR_SYS_ERROR;
515 return DMLERR_INVALIDPARAMETER;
518 /* Check 3 - must supply different callback address */
520 if ( this_instance->CallBack == reference_inst->CallBack)
522 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
523 return DMLERR_SYS_ERROR;
524 return DMLERR_DLL_USAGE;
527 reference_inst = reference_inst->Next_Entry;
529 /* All cleared, add to chain */
531 TRACE(ddeml,"Application Instance checks finished\n");
532 if ((err_no = IncrementInstanceId())) return err_no;
533 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0)) return DMLERR_SYS_ERROR;
534 reference_inst->Next_Entry = this_instance;
536 *pidInst = this_instance->Instance_id;
537 TRACE(ddeml,"New application instance processing finished OK\n");
539 /* Reinitialisation situation --- FIX */
540 TRACE(ddeml,"reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
541 WaitForSingleObject(handle_mutex,1000);
542 if ( (err_no=GetLastError()) != 0 )
545 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
547 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
548 HeapFree(SystemHeap, 0, this_instance);
549 return DMLERR_SYS_ERROR;
551 if (DDE_Handle_Table_Base == NULL )
553 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1)) return DMLERR_SYS_ERROR;
554 return DMLERR_DLL_USAGE;
556 HeapFree(SystemHeap, 0, this_instance); /* finished - release heap space used as work store */
557 /* can't reinitialise if we have initialised nothing !! */
558 reference_inst = DDE_Handle_Table_Base;
559 /* must first check if we have been given a valid instance to re-initialise !! how do we do that ? */
561 * MS allows initialisation without specifying a callback, should we allow addition of the
562 * callback by a later call to initialise ? - if so this lot will have to change
564 while ( reference_inst->Next_Entry != NULL )
566 if ( *pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
568 /* Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY */
570 if ( reference_inst->Client_only )
572 if ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS)
574 /* i.e. Was set to Client-only and through APPCMD_CLIENTONLY */
576 if ( ! ( afCmd & APPCMD_CLIENTONLY))
578 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
579 return DMLERR_SYS_ERROR;
580 return DMLERR_DLL_USAGE;
584 /* Check 2 - cannot change monitor modes */
586 if ( this_instance->Monitor != reference_inst->Monitor)
588 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
589 return DMLERR_SYS_ERROR;
590 return DMLERR_DLL_USAGE;
593 /* Check 3 - trying to set Client-only via APPCMD when not set so previously */
595 if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
597 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
598 return DMLERR_SYS_ERROR;
599 return DMLERR_DLL_USAGE;
603 reference_inst = reference_inst->Next_Entry;
605 if ( reference_inst->Next_Entry == NULL )
607 /* Crazy situation - trying to re-initialize something that has not beeen initialized !!
609 * Manual does not say what we do, cannot return DMLERR_NOT_INITIALIZED so what ?
611 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
612 return DMLERR_SYS_ERROR;
613 return DMLERR_INVALIDPARAMETER;
615 /* All checked - change relevant flags */
617 reference_inst->CBF_Flags = this_instance->CBF_Flags;
618 reference_inst->Client_only = this_instance->Client_only;
619 reference_inst->Monitor_flags = this_instance->Monitor_flags;
620 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
621 return DMLERR_SYS_ERROR;
624 return DMLERR_NO_ERROR;
628 /*****************************************************************
629 * DdeUninitialize16 (DDEML.3)
631 BOOL16 WINAPI DdeUninitialize16( DWORD idInst )
633 FIXME(ddeml," stub calling DdeUninitialize\n");
634 return (BOOL16)DdeUninitialize( idInst );
638 /*****************************************************************
639 * DdeUninitialize [USER32.119] Frees DDEML resources
642 * idInst [I] Instance identifier
649 BOOL WINAPI DdeUninitialize( DWORD idInst )
651 /* Stage one - check if we have a handle for this instance
653 SECURITY_ATTRIBUTES s_attrib;
656 if ( DDE_Max_Assigned_Instance == 0 )
658 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
661 WaitForSingleObject(handle_mutex,1000);
662 if ( (err_no=GetLastError()) != 0 )
664 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
666 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
667 return DMLERR_SYS_ERROR;
669 TRACE(ddeml,"Handle Mutex created/reserved\n");
670 /* First check instance
672 this_instance = Find_Instance_Entry(idInst);
673 if ( this_instance == NULL )
675 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return FALSE;
677 * Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
681 FIXME(ddeml, "(%ld): partial stub\n", idInst);
683 /* Free the nodes that were not freed by this instance
684 * and remove the nodes from the list of HSZ nodes.
686 FreeAndRemoveHSZNodes( idInst );
688 /* OK now delete the instance handle itself */
690 if ( DDE_Handle_Table_Base == this_instance )
692 /* special case - the first/only entry
694 DDE_Handle_Table_Base = this_instance->Next_Entry;
699 reference_inst->Next_Entry = DDE_Handle_Table_Base;
700 while ( reference_inst->Next_Entry != this_instance )
702 reference_inst = this_instance->Next_Entry;
704 reference_inst->Next_Entry = this_instance->Next_Entry;
706 /* release the mutex and the heap entry
708 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,TRUE))
710 /* should record something here, but nothing left to hang it from !!
718 /*****************************************************************
719 * DdeConnectList16 [DDEML.4]
722 HCONVLIST WINAPI DdeConnectList16( DWORD idInst, HSZ hszService, HSZ hszTopic,
723 HCONVLIST hConvList, LPCONVCONTEXT16 pCC )
725 return DdeConnectList(idInst, hszService, hszTopic, hConvList,
730 /******************************************************************************
731 * DdeConnectList [USER32.93] Establishes conversation with DDE servers
734 * idInst [I] Instance identifier
735 * hszService [I] Handle to service name string
736 * hszTopic [I] Handle to topic name string
737 * hConvList [I] Handle to conversation list
738 * pCC [I] Pointer to structure with context data
741 * Success: Handle to new conversation list
744 HCONVLIST WINAPI DdeConnectList( DWORD idInst, HSZ hszService, HSZ hszTopic,
745 HCONVLIST hConvList, LPCONVCONTEXT pCC )
747 FIXME(ddeml, "(%ld,%ld,%ld,%ld,%p): stub\n", idInst, hszService, hszTopic,
753 /*****************************************************************
754 * DdeQueryNextServer16 [DDEML.5]
756 HCONV WINAPI DdeQueryNextServer16( HCONVLIST hConvList, HCONV hConvPrev )
758 return DdeQueryNextServer(hConvList, hConvPrev);
762 /*****************************************************************
763 * DdeQueryNextServer [USER32.112]
765 HCONV WINAPI DdeQueryNextServer( HCONVLIST hConvList, HCONV hConvPrev )
767 FIXME(ddeml, "(%ld,%ld): stub\n",hConvList,hConvPrev);
771 /*****************************************************************
772 * DdeQueryStringA [USER32.113]
774 *****************************************************************
778 * Vn Date Author Comment
780 * 1.0 Dec 1998 Corel/Macadamian Initial version
781 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
784 DWORD WINAPI DdeQueryStringA(DWORD idInst, HSZ hsz, LPSTR psz, DWORD cchMax, INT iCodePage)
787 CHAR pString[MAX_BUFFER_LEN];
790 "(%ld, 0x%lx, %p, %ld, %d): partial stub\n",
796 if ( DDE_Max_Assigned_Instance == 0 )
798 /* Nothing has been initialised - exit now ! */
799 /* needs something for DdeGetLAstError even if the manual doesn't say so */
802 WaitForSingleObject(handle_mutex,1000);
803 if ( (err_no=GetLastError()) != 0 )
805 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
807 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
808 /* needs something for DdeGetLAstError even if the manual doesn't say so */
811 TRACE(ddeml,"Handle Mutex created/reserved\n");
813 /* First check instance
815 reference_inst = Find_Instance_Entry(idInst);
816 if ( reference_inst == NULL )
818 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return FALSE;
820 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
825 if( iCodePage == CP_WINANSI )
827 /* If psz is null, we have to return only the length
833 cchMax = MAX_BUFFER_LEN;
836 ret = GlobalGetAtomNameA( hsz, (LPSTR)psz, cchMax );
838 TRACE(ddeml,"returning pointer\n");
842 /*****************************************************************
843 * DdeQueryStringW [USER32.114]
845 *****************************************************************
849 * Vn Date Author Comment
851 * 1.0 Dec 1998 Corel/Macadamian Initial version
855 DWORD WINAPI DdeQueryStringW(DWORD idInst, HSZ hsz, LPWSTR psz, DWORD cchMax, INT iCodePage)
858 WCHAR pString[MAX_BUFFER_LEN];
862 "(%ld, 0x%lx, %p, %ld, %d): stub\n",
869 if( iCodePage == CP_WINUNICODE )
871 /* If psz is null, we have to return only the length
877 cchMax = MAX_BUFFER_LEN;
878 /* Note: According to documentation if the psz parameter
879 * was NULL this API must return the length of the string in bytes.
881 factor = (int) sizeof(WCHAR)/sizeof(BYTE);
883 ret = GlobalGetAtomNameW( hsz, (LPWSTR)psz, cchMax ) * factor;
888 /*****************************************************************
890 * DdeQueryString16 (DDEML.23)
892 ******************************************************************
896 * Vn Date Author Comment
898 * 1.0 March 1999 K Matthews stub only
901 DWORD WINAPI DdeQueryString16(DWORD idInst, HSZ hsz, LPSTR lpsz, DWORD cchMax, int codepage)
903 FIXME(ddeml,"(%ld, 0x%lx, %p, %ld, %d): stub \n",
913 /*****************************************************************
914 * DdeDisconnectList (DDEML.6)
916 BOOL16 WINAPI DdeDisconnectList16( HCONVLIST hConvList )
918 return (BOOL16)DdeDisconnectList(hConvList);
922 /******************************************************************************
923 * DdeDisconnectList [USER32.98] Destroys list and terminates conversations
929 BOOL WINAPI DdeDisconnectList(
930 HCONVLIST hConvList) /* [in] Handle to conversation list */
932 FIXME(ddeml, "(%ld): stub\n", hConvList);
937 /*****************************************************************
938 * DdeConnect16 (DDEML.7)
940 HCONV WINAPI DdeConnect16( DWORD idInst, HSZ hszService, HSZ hszTopic,
941 LPCONVCONTEXT16 pCC )
943 FIXME( ddeml, "empty stub\n" );
948 /*****************************************************************
949 * DdeConnect (USER32.92)
951 HCONV WINAPI DdeConnect( DWORD idInst, HSZ hszService, HSZ hszTopic,
954 FIXME(ddeml, "(0x%lx,%ld,%ld,%p): stub\n",idInst,hszService,hszTopic,
960 /*****************************************************************
961 * DdeDisconnect16 (DDEML.8)
963 BOOL16 WINAPI DdeDisconnect16( HCONV hConv )
965 return (BOOL16)DdeDisconnect( hConv );
968 /*****************************************************************
969 * DdeSetUserHandle16 (DDEML.10)
971 BOOL16 WINAPI DdeSetUserHandle16( HCONV hConv, DWORD id, DWORD hUser )
973 FIXME( ddeml, "(%ld,%ld,%ld): stub\n",hConv,id, hUser );
977 /*****************************************************************
978 * DdeCreateDataHandle16 (DDEML.14)
980 HDDEDATA WINAPI DdeCreateDataHandle16( DWORD idInst, LPBYTE pSrc, DWORD cb,
981 DWORD cbOff, HSZ hszItem, UINT16 wFmt,
984 return DdeCreateDataHandle(idInst,
993 /*****************************************************************
994 * DdeCreateDataHandle (USER32.94)
996 HDDEDATA WINAPI DdeCreateDataHandle( DWORD idInst, LPBYTE pSrc, DWORD cb,
997 DWORD cbOff, HSZ hszItem, UINT wFmt,
1001 "(%ld,%p,%ld,%ld,0x%lx,%d,%d): stub\n",
1013 /*****************************************************************
1014 * DdeDisconnect (USER32.97)
1016 BOOL WINAPI DdeDisconnect( HCONV hConv )
1018 FIXME( ddeml, "empty stub\n" );
1023 /*****************************************************************
1024 * DdeReconnect (DDEML.37) (USER32.115)
1026 HCONV WINAPI DdeReconnect( HCONV hConv )
1028 FIXME( ddeml, "empty stub\n" );
1033 /*****************************************************************
1034 * DdeCreateStringHandle16 (DDEML.21)
1036 HSZ WINAPI DdeCreateStringHandle16( DWORD idInst, LPCSTR str, INT16 codepage )
1038 return DdeCreateStringHandleA( idInst, str, codepage );
1042 /*****************************************************************
1043 * DdeCreateStringHandleA [USER32.95]
1046 * Success: String handle
1049 *****************************************************************
1053 * Vn Date Author Comment
1055 * 1.0 Dec 1998 Corel/Macadamian Initial version
1056 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1059 HSZ WINAPI DdeCreateStringHandleA( DWORD idInst, LPCSTR psz, INT codepage )
1062 TRACE(ddeml, "(%ld,%s,%d): partial stub\n",idInst,debugstr_a(psz),codepage);
1065 if ( DDE_Max_Assigned_Instance == 0 )
1067 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1070 WaitForSingleObject(handle_mutex,1000);
1071 if ( (err_no=GetLastError()) != 0 )
1073 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1075 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1076 return DMLERR_SYS_ERROR;
1078 TRACE(ddeml,"Handle Mutex created/reserved\n");
1080 /* First check instance
1082 reference_inst = Find_Instance_Entry(idInst);
1083 if ( reference_inst == NULL )
1085 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return 0;
1087 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1092 if (codepage==CP_WINANSI)
1094 hsz = GlobalAddAtomA (psz);
1095 /* Save the handle so we know to clean it when
1096 * uninitialize is called.
1098 InsertHSZNode( hsz );
1099 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE))
1101 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1104 TRACE(ddeml,"Returning pointer\n");
1107 TRACE(ddeml,"Returning error\n");
1112 /******************************************************************************
1113 * DdeCreateStringHandleW [USER32.96] Creates handle to identify string
1116 * Success: String handle
1119 *****************************************************************
1123 * Vn Date Author Comment
1125 * 1.0 Dec 1998 Corel/Macadamian Initial version
1126 * 1.1 Mar 1999 Keith Matthews Added links to instance table and related processing
1129 HSZ WINAPI DdeCreateStringHandleW(
1130 DWORD idInst, /* [in] Instance identifier */
1131 LPCWSTR psz, /* [in] Pointer to string */
1132 INT codepage) /* [in] Code page identifier */
1136 TRACE(ddeml, "(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1139 if ( DDE_Max_Assigned_Instance == 0 )
1141 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1144 WaitForSingleObject(handle_mutex,1000);
1145 if ( (err_no=GetLastError()) != 0 )
1147 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1149 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1150 return DMLERR_SYS_ERROR;
1152 TRACE(ddeml,"CreateString - Handle Mutex created/reserved\n");
1154 /* First check instance
1156 reference_inst = Find_Instance_Entry(idInst);
1157 if ( reference_inst == NULL )
1159 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return 0;
1161 Needs something here to record NOT_INITIALIZED ready for DdeGetLastError
1166 FIXME(ddeml, "(%ld,%s,%d): partial stub\n",idInst,debugstr_w(psz),codepage);
1168 if (codepage==CP_WINUNICODE)
1170 Should we be checking this against the unicode/ascii nature of the call to DdeInitialize ?
1173 hsz = GlobalAddAtomW (psz);
1174 /* Save the handle so we know to clean it when
1175 * uninitialize is called.
1177 InsertHSZNode( hsz );
1178 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE))
1180 reference_inst->Last_Error = DMLERR_SYS_ERROR;
1183 TRACE(ddeml,"Returning pointer\n");
1186 TRACE(ddeml,"Returning error\n");
1191 /*****************************************************************
1192 * DdeFreeStringHandle16 (DDEML.22)
1194 BOOL16 WINAPI DdeFreeStringHandle16( DWORD idInst, HSZ hsz )
1196 FIXME(ddeml,"idInst %ld hsz 0x%lx\n",idInst,hsz);
1197 return (BOOL)DdeFreeStringHandle( idInst, hsz );
1201 /*****************************************************************
1202 * DdeFreeStringHandle (USER32.101)
1203 * RETURNS: success: nonzero
1206 *****************************************************************
1210 * Vn Date Author Comment
1212 * 1.0 Dec 1998 Corel/Macadamian Initial version
1213 * 1.1 Apr 1999 Keith Matthews Added links to instance table and related processing
1216 BOOL WINAPI DdeFreeStringHandle( DWORD idInst, HSZ hsz )
1218 TRACE(ddeml, "(%ld,%ld): \n",idInst,hsz);
1219 if ( DDE_Max_Assigned_Instance == 0 )
1221 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1224 if ( ( err_no = GetLastError()) != 0 )
1226 /* something earlier failed !! */
1227 ERR(ddeml,"Error %li before WaitForSingleObject - trying to continue\n",err_no);
1229 WaitForSingleObject(handle_mutex,1000);
1230 if ( (err_no=GetLastError()) != 0 )
1232 /* FIXME - needs refinement with popup for timeout, also is timeout interval OK */
1234 ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
1235 return DMLERR_SYS_ERROR;
1237 TRACE(ddeml,"Handle Mutex created/reserved\n");
1239 /* First check instance
1241 reference_inst = Find_Instance_Entry(idInst);
1242 if ( (reference_inst == NULL) | (reference_inst->Node_list == NULL))
1244 if ( Release_reserved_mutex(handle_mutex,"handle_mutex",FALSE,FALSE)) return TRUE;
1245 /* Nothing has been initialised - exit now ! can return TRUE since effect is the same */
1250 /* Remove the node associated with this HSZ.
1252 RemoveHSZNode( hsz );
1253 /* Free the string associated with this HSZ.
1255 return GlobalDeleteAtom (hsz) ? 0 : hsz;
1259 /*****************************************************************
1260 * DdeFreeDataHandle16 (DDEML.19)
1262 BOOL16 WINAPI DdeFreeDataHandle16( HDDEDATA hData )
1264 return (BOOL)DdeFreeDataHandle( hData );
1268 /*****************************************************************
1269 * DdeFreeDataHandle (USER32.100)
1271 BOOL WINAPI DdeFreeDataHandle( HDDEDATA hData )
1273 FIXME( ddeml, "empty stub\n" );
1280 /*****************************************************************
1281 * DdeKeepStringHandle16 (DDEML.24)
1283 BOOL16 WINAPI DdeKeepStringHandle16( DWORD idInst, HSZ hsz )
1285 return (BOOL)DdeKeepStringHandle( idInst, hsz );
1289 /*****************************************************************
1290 * DdeKeepStringHandle (USER32.108)
1292 BOOL WINAPI DdeKeepStringHandle( DWORD idInst, HSZ hsz )
1294 FIXME( ddeml, "empty stub\n" );
1299 /*****************************************************************
1300 * DdeClientTransaction16 (DDEML.11)
1302 HDDEDATA WINAPI DdeClientTransaction16( LPVOID pData, DWORD cbData,
1303 HCONV hConv, HSZ hszItem, UINT16 wFmt,
1304 UINT16 wType, DWORD dwTimeout,
1307 return DdeClientTransaction( (LPBYTE)pData, cbData, hConv, hszItem,
1308 wFmt, wType, dwTimeout, pdwResult );
1312 /*****************************************************************
1313 * DdeClientTransaction (USER32.90)
1315 HDDEDATA WINAPI DdeClientTransaction( LPBYTE pData, DWORD cbData,
1316 HCONV hConv, HSZ hszItem, UINT wFmt,
1317 UINT wType, DWORD dwTimeout,
1320 FIXME( ddeml, "empty stub\n" );
1324 /*****************************************************************
1326 * DdeAbandonTransaction16 (DDEML.12)
1329 BOOL16 WINAPI DdeAbandonTransaction16( DWORD idInst, HCONV hConv,
1330 DWORD idTransaction )
1332 FIXME( ddeml, "empty stub\n" );
1337 /*****************************************************************
1339 * DdeAbandonTransaction (USER32.87)
1341 ******************************************************************
1345 * Vn Date Author Comment
1347 * 1.0 March 1999 K Matthews stub only
1349 BOOL WINAPI DdeAbandonTransaction( DWORD idInst, HCONV hConv,
1350 DWORD idTransaction )
1352 FIXME( ddeml, "empty stub\n" );
1356 /*****************************************************************
1357 * DdePostAdvise16 [DDEML.13]
1359 BOOL16 WINAPI DdePostAdvise16( DWORD idInst, HSZ hszTopic, HSZ hszItem )
1361 return (BOOL16)DdePostAdvise(idInst, hszTopic, hszItem);
1365 /******************************************************************************
1366 * DdePostAdvise [USER32.110] Send transaction to DDE callback function.
1372 BOOL WINAPI DdePostAdvise(
1373 DWORD idInst, /* [in] Instance identifier */
1374 HSZ hszTopic, /* [in] Handle to topic name string */
1375 HSZ hszItem) /* [in] Handle to item name string */
1377 FIXME(ddeml, "(%ld,%ld,%ld): stub\n",idInst,hszTopic,hszItem);
1382 /*****************************************************************
1383 * DdeAddData16 (DDEML.15)
1385 HDDEDATA WINAPI DdeAddData16( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1388 FIXME( ddeml, "empty stub\n" );
1392 /*****************************************************************
1394 * DdeAddData (USER32.89)
1396 ******************************************************************
1400 * Vn Date Author Comment
1402 * 1.0 March 1999 K Matthews stub only
1404 HDDEDATA WINAPI DdeAddData( HDDEDATA hData, LPBYTE pSrc, DWORD cb,
1407 FIXME( ddeml, "empty stub\n" );
1412 /*****************************************************************
1414 * DdeImpersonateClient (USER32.105)
1416 ******************************************************************
1420 * Vn Date Author Comment
1422 * 1.0 March 1999 K Matthews stub only
1425 BOOL WINAPI DdeImpersonateClient( HCONV hConv)
1427 FIXME( ddeml, "empty stub\n" );
1432 /*****************************************************************
1434 * DdeSetQualityOfService (USER32.116)
1436 ******************************************************************
1440 * Vn Date Author Comment
1442 * 1.0 March 1999 K Matthews stub only
1445 BOOL WINAPI DdeSetQualityOfService( HWND hwndClient, CONST SECURITY_QUALITY_OF_SERVICE *pqosNew,
1446 PSECURITY_QUALITY_OF_SERVICE pqosPrev)
1448 FIXME( ddeml, "empty stub\n" );
1452 /*****************************************************************
1454 * DdeSetUserHandle (USER32.117)
1456 ******************************************************************
1460 * Vn Date Author Comment
1462 * 1.0 March 1999 K Matthews stub only
1465 BOOL WINAPI DdeSetUserHandle( HCONV hConv, DWORD id, DWORD hUser)
1467 FIXME( ddeml, "empty stub\n" );
1471 /******************************************************************************
1472 * DdeGetData [USER32.102] Copies data from DDE object ot local buffer
1475 * Size of memory object associated with handle
1477 DWORD WINAPI DdeGetData(
1478 HDDEDATA hData, /* [in] Handle to DDE object */
1479 LPBYTE pDst, /* [in] Pointer to destination buffer */
1480 DWORD cbMax, /* [in] Amount of data to copy */
1481 DWORD cbOff) /* [in] Offset to beginning of data */
1483 FIXME(ddeml, "(%ld,%p,%ld,%ld): stub\n",hData,pDst,cbMax,cbOff);
1488 /*****************************************************************
1489 * DdeGetData16 [DDEML.16]
1491 DWORD WINAPI DdeGetData16(
1497 return DdeGetData(hData, pDst, cbMax, cbOff);
1501 /*****************************************************************
1502 * DdeAccessData16 (DDEML.17)
1504 LPBYTE WINAPI DdeAccessData16( HDDEDATA hData, LPDWORD pcbDataSize )
1506 return DdeAccessData(hData, pcbDataSize);
1509 /*****************************************************************
1510 * DdeAccessData (USER32.88)
1512 LPBYTE WINAPI DdeAccessData( HDDEDATA hData, LPDWORD pcbDataSize )
1514 FIXME( ddeml, "(%ld,%p): stub\n", hData, pcbDataSize);
1518 /*****************************************************************
1519 * DdeUnaccessData16 (DDEML.18)
1521 BOOL16 WINAPI DdeUnaccessData16( HDDEDATA hData )
1523 return DdeUnaccessData(hData);
1526 /*****************************************************************
1527 * DdeUnaccessData (USER32.118)
1529 BOOL WINAPI DdeUnaccessData( HDDEDATA hData )
1531 FIXME( ddeml, "(0x%lx): stub\n", hData);
1536 /*****************************************************************
1537 * DdeEnableCallback16 (DDEML.26)
1539 BOOL16 WINAPI DdeEnableCallback16( DWORD idInst, HCONV hConv, UINT16 wCmd )
1541 return DdeEnableCallback(idInst, hConv, wCmd);
1544 /*****************************************************************
1545 * DdeEnableCallback (USER32.99)
1547 BOOL WINAPI DdeEnableCallback( DWORD idInst, HCONV hConv, UINT wCmd )
1549 FIXME( ddeml, "(%ld, 0x%lx, %d) stub\n", idInst, hConv, wCmd);
1554 /*****************************************************************
1555 * DdeNameService16 (DDEML.27)
1557 HDDEDATA WINAPI DdeNameService16( DWORD idInst, HSZ hsz1, HSZ hsz2,
1560 return DdeNameService( idInst, hsz1, hsz2, afCmd );
1564 /******************************************************************************
1565 * DdeNameService [USER32.109] {Un}registers service name of DDE server
1568 * idInst [I] Instance identifier
1569 * hsz1 [I] Handle to service name string
1571 * afCmd [I] Service name flags
1577 HDDEDATA WINAPI DdeNameService( DWORD idInst, HSZ hsz1, HSZ hsz2,
1580 FIXME(ddeml, "(%ld,%ld,%ld,%d): stub\n",idInst,hsz1,hsz2,afCmd);
1585 /*****************************************************************
1586 * DdeGetLastError16 (DDEML.20)
1588 UINT16 WINAPI DdeGetLastError16( DWORD idInst )
1590 return (UINT16)DdeGetLastError( idInst );
1594 /******************************************************************************
1595 * DdeGetLastError [USER32.103] Gets most recent error code
1598 * idInst [I] Instance identifier
1603 UINT WINAPI DdeGetLastError( DWORD idInst )
1605 FIXME(ddeml, "(%ld): stub\n",idInst);
1610 /*****************************************************************
1611 * DdeCmpStringHandles16 (DDEML.36)
1613 int WINAPI DdeCmpStringHandles16( HSZ hsz1, HSZ hsz2 )
1615 return DdeCmpStringHandles(hsz1, hsz2);
1618 /*****************************************************************
1619 * DdeCmpStringHandles (USER32.91)
1621 * Compares the value of two string handles. This comparison is
1622 * not case sensitive.
1625 * -1 The value of hsz1 is zero or less than hsz2
1626 * 0 The values of hsz 1 and 2 are the same or both zero.
1627 * 1 The value of hsz2 is zero of less than hsz1
1629 int WINAPI DdeCmpStringHandles( HSZ hsz1, HSZ hsz2 )
1631 CHAR psz1[MAX_BUFFER_LEN];
1632 CHAR psz2[MAX_BUFFER_LEN];
1636 TRACE( ddeml, "handle 1, handle 2\n" );
1638 ret1 = GlobalGetAtomNameA( hsz1, psz1, MAX_BUFFER_LEN );
1639 ret2 = GlobalGetAtomNameA( hsz2, psz2, MAX_BUFFER_LEN );
1640 /* Make sure we found both strings.
1642 if( ret1 == 0 && ret2 == 0 )
1644 /* If both are not found, return both "zero strings".
1648 else if( ret1 == 0 )
1650 /* If hsz1 is a not found, return hsz1 is "zero string".
1654 else if( ret2 == 0 )
1656 /* If hsz2 is a not found, return hsz2 is "zero string".
1662 /* Compare the two strings we got ( case insensitive ).
1664 ret = strcasecmp( psz1, psz2 );
1665 /* Since strcmp returns any number smaller than
1666 * 0 when the first string is found to be less than
1667 * the second one we must make sure we are returning
1668 * the proper values.
1683 /*****************************************************************
1684 * PackDDElParam (USER32.414)
1690 UINT WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi)
1692 FIXME(ddeml, "stub.\n");
1697 /*****************************************************************
1698 * UnpackDDElParam (USER32.562)
1704 UINT WINAPI UnpackDDElParam(UINT msg, UINT lParam,
1705 UINT *uiLo, UINT *uiHi)
1707 FIXME(ddeml, "stub.\n");
1712 /*****************************************************************
1713 * FreeDDElParam (USER32.204)
1719 UINT WINAPI FreeDDElParam(UINT msg, UINT lParam)
1721 FIXME(ddeml, "stub.\n");
1725 /*****************************************************************
1726 * ReuseDDElParam (USER32.446)
1729 UINT WINAPI ReuseDDElParam(UINT lParam, UINT msgIn, UINT msgOut,
1730 UINT uiLi, UINT uiHi)
1732 FIXME(ddeml, "stub.\n");
1736 /******************************************************************
1737 * DdeQueryConvInfo16 (DDEML.9)
1740 UINT16 WINAPI DdeQueryConvInfo16( HCONV hconv, DWORD idTransaction , LPCONVINFO16 lpConvInfo)
1742 FIXME(ddeml,"stub.\n");
1747 /******************************************************************
1748 * DdeQueryConvInfo (USER32.111)
1751 UINT WINAPI DdeQueryConvInfo( HCONV hconv, DWORD idTransaction , LPCONVINFO lpConvInfo)
1753 FIXME(ddeml,"stub.\n");