1st cut implementation of DdeInitialize32W and supporting code.

diff --git a/include/ddeml.h b/include/ddeml.h
index dfb08ee..cf76a8d 100644
--- a/include/ddeml.h
+++ b/include/ddeml.h
@@ -16,11 +16,119 @@
 #define CP_WINUNICODE   1200
 
 #define MSGF_DDEMGR 0x8001
+/***************************************************
+
+      FLAGS Section - copied from Microsoft SDK as must be standard, probably Copyright Microsoft Corporation
+
+***************************************************/
+
+/*
+ * Callback filter flags for use with standard apps.
+ */
+
+#define     CBF_FAIL_SELFCONNECTIONS     0x00001000
+#define     CBF_FAIL_CONNECTIONS         0x00002000
+#define     CBF_FAIL_ADVISES             0x00004000
+#define     CBF_FAIL_EXECUTES            0x00008000
+#define     CBF_FAIL_POKES               0x00010000
+#define     CBF_FAIL_REQUESTS            0x00020000
+#define     CBF_FAIL_ALLSVRXACTIONS      0x0003f000
+
+#define     CBF_SKIP_CONNECT_CONFIRMS    0x00040000
+#define     CBF_SKIP_REGISTRATIONS       0x00080000
+#define     CBF_SKIP_UNREGISTRATIONS     0x00100000
+#define     CBF_SKIP_DISCONNECTS         0x00200000
+#define     CBF_SKIP_ALLNOTIFICATIONS    0x003c0000
+
+/*
+ * Application command flags
+ */
+#define     APPCMD_CLIENTONLY            0x00000010L
+#define     APPCMD_FILTERINITS           0x00000020L
+#define     APPCMD_MASK                  0x00000FF0L
+
+/*
+ * Application classification flags
+ */
+
+#define     APPCLASS_STANDARD            0x00000000L
+#define     APPCLASS_MONITOR             0x00000001L
+#define     APPCLASS_MASK                0x0000000FL
+
+/*
+ * Callback filter flags for use with MONITOR apps - 0 implies no monitor
+ * callbacks.
+ */
+#define     MF_HSZ_INFO                  0x01000000
+#define     MF_SENDMSGS                  0x02000000
+#define     MF_POSTMSGS                  0x04000000
+#define     MF_CALLBACKS                 0x08000000
+#define     MF_ERRORS                    0x10000000
+#define     MF_LINKS                     0x20000000
+#define     MF_CONV                      0x40000000
+
+#define     MF_MASK                      0xFF000000
+
+/*
+ *	DdeNameService service name flags
+ */
+
+#define     DNS_REGISTER		 0x0001
+#define     DNS_UNREGISTER		 0x0002
+#define     DNS_FILTERON		 0x0004
+#define     DNS_FILTEROFF         	 0x0008
+
+
+/****************************************************
+
+      End of Flags section
+
+****************************************************/
+
+/****************************************************
+
+      Return Codes section again copied from SDK as must be same
+
+*****************************************************/
+
+#define     DMLERR_NO_ERROR                    0       /* must be 0 */
+
+#define     DMLERR_FIRST                       0x4000
+
+#define     DMLERR_ADVACKTIMEOUT               0x4000
+#define     DMLERR_BUSY                        0x4001
+#define     DMLERR_DATAACKTIMEOUT              0x4002
+#define     DMLERR_DLL_NOT_INITIALIZED         0x4003
+#define     DMLERR_DLL_USAGE                   0x4004
+#define     DMLERR_EXECACKTIMEOUT              0x4005
+#define     DMLERR_INVALIDPARAMETER            0x4006
+#define     DMLERR_LOW_MEMORY                  0x4007
+#define     DMLERR_MEMORY_ERROR                0x4008
+#define     DMLERR_NOTPROCESSED                0x4009
+#define     DMLERR_NO_CONV_ESTABLISHED         0x400a
+#define     DMLERR_POKEACKTIMEOUT              0x400b
+#define     DMLERR_POSTMSG_FAILED              0x400c
+#define     DMLERR_REENTRANCY                  0x400d
+#define     DMLERR_SERVER_DIED                 0x400e
+#define     DMLERR_SYS_ERROR                   0x400f
+#define     DMLERR_UNADVACKTIMEOUT             0x4010
+#define     DMLERR_UNFOUND_QUEUE_ID            0x4011
+
+#define     DMLERR_LAST                        0x4011
+
+/*****************************************************
+
+      End of Return Codes and Microsoft section
+
+******************************************************/
+
+
 
 typedef DWORD HCONVLIST;
 typedef DWORD HCONV;
 typedef DWORD HSZ;
 typedef DWORD HDDEDATA;
+typedef CHAR *LPTSTR;
 
 typedef HDDEDATA (CALLBACK *PFNCALLBACK16)(UINT16,UINT16,HCONV,HSZ,HSZ,
                                            HDDEDATA,DWORD,DWORD);
@@ -28,6 +136,12 @@
                                            HDDEDATA,DWORD,DWORD);
 DECL_WINELIB_TYPE(PFNCALLBACK)
 
+/***************************************************
+
+	Externally visible data structures
+
+***************************************************/
+
 typedef struct
 {
     UINT16  cb;
@@ -48,6 +162,24 @@
     DWORD   dwSecurity;
 } CONVCONTEXT32, *LPCONVCONTEXT32;
 
+//  Internal data structures
+
+      /*  entry for handle table     */
+typedef struct DDE_HANDLE_ENTRY {
+    BOOL16              Monitor;        // have these two as full Booleans cos they'll be tested frequently
+    BOOL16              Client_only;    // bit wasteful of space but it will be faster
+    BOOL16		Unicode;	/* Flag to indicate Win32 API used to initialise */
+    BOOL16		Win16;		/* flag to indicate Win16 API used to initialize */
+    LPDWORD            	Instance_id;  // needed to track monitor usage
+    struct DDE_HANDLE_ENTRY    *Next_Entry;
+    PFNCALLBACK32	CallBack;
+    DWORD               CBF_Flags;
+    DWORD               Monitor_flags;
+    UINT32              Txn_count;      // count transactions open to simplify closure
+} DDE_HANDLE_ENTRY;
+
+//            Interface Definitions
+
 DECL_WINELIB_TYPE(CONVCONTEXT)
 DECL_WINELIB_TYPE(LPCONVCONTEXT)
 
diff --git a/misc/ddeml.c b/misc/ddeml.c
index dceb722..ebc7bda 100644
--- a/misc/ddeml.c
+++ b/misc/ddeml.c
@@ -3,6 +3,7 @@
  *
  * Copyright 1997 Alexandre Julliard
  * Copyright 1997 Len White
+ * Copyright 1999 Keith Matthews
  */
 
 /* Only empty stubs for now */
@@ -12,10 +13,10 @@
 #include "ddeml.h"
 #include "debug.h"
 #include "windows.h"
+#include "wintypes.h"
+#include "winerror.h"
 #include "heap.h"
-
-/* FIXME: What are these values? */
-#define DMLERR_NO_ERROR		0
+#include "shm_semaph.h"
 
 /* Has defined in atom.c file.
  */
@@ -25,13 +26,35 @@
  */
 #define MAX_BUFFER_LEN            (MAX_ATOM_LEN + 1)
 
-static LONG     DDE_current_handle;
+
+static DDE_HANDLE_ENTRY *DDE_Handle_Table_Base = NULL;
+static LPDWORD 		DDE_Max_Assigned_Instance = 0;  // OK for present, may have to worry about wrap-around later
+static const char	inst_string[]= "DDEMaxInstance";
+static LPCWSTR 		DDEInstanceAccess = (LPCWSTR)&inst_string;
+static const char	handle_string[] = "DDEHandleAccess";
+static LPCWSTR      	DDEHandleAccess = (LPCWSTR)&handle_string;
+static HANDLE32	     	inst_count_mutex = 0;
+static HANDLE32	     	handle_mutex = 0;
+       DDE_HANDLE_ENTRY *this_instance;
+       SECURITY_ATTRIBUTES *s_att= NULL;
+       DWORD 	     	err_no = 0;
+
+/*  typedef struct {
+	DWORD		nLength;
+	LPVOID		lpSecurityDescriptor;
+	BOOL32		bInheritHandle;
+}	SECURITY_ATTRIBUTES; */
+
+#define TRUE	1
+#define FALSE	0
+
+
 
 /* This is a simple list to keep track of the strings created
  * by DdeCreateStringHandle.  The list is used to free
  * the strings whenever DdeUninitialize is called.
  * This mechanism is not complete and does not handle multiple instances.
- * Most of the DDE API use a DWORD parameter indicating witch instance
+ * Most of the DDE API use a DWORD parameter indicating which instance
  * of a given program is calling them.  The API are supposed to
  * associate the data to the instance that created it.
  */
@@ -51,6 +74,15 @@
  *            RemoveHSZNodes    (INTERNAL)
  *
  * Remove a node from the list of HSZ nodes.
+ *
+ ******************************************************************************
+ *
+ *	Change History
+ *
+ *  Vn       Date    	Author         		Comment
+ *
+ *  1.0      Dec 1998  Corel/Macadamian    Initial version
+ *
  */
 static void RemoveHSZNode( DWORD idInst, HSZ hsz )
 {
@@ -103,6 +135,15 @@
  *
  * Frees up all the strings still allocated in the list and
  * remove all the nodes from the list of HSZ nodes.
+ *
+ ******************************************************************************
+ *
+ *	Change History
+ *
+ *  Vn       Date    	Author         		Comment
+ *
+ *  1.0      Dec 1998  Corel/Macadamian    Initial version
+ *
  */
 static void FreeAndRemoveHSZNodes( DWORD idInst )
 {
@@ -118,6 +159,15 @@
  *            InsertHSZNode    (INTERNAL)
  *
  * Insert a node to the head of the list.
+ *
+ ******************************************************************************
+ *
+ *	Change History
+ *
+ *  Vn       Date    	Author         		Comment
+ *
+ *  1.0      Dec 1998  Corel/Macadamian    Initial version
+ *
  */
 static void InsertHSZNode( DWORD idInst, HSZ hsz )
 {
@@ -143,6 +193,81 @@
     }
 }
 
+/******************************************************************************
+ *	Release_reserved_mutex
+ *
+ *	generic routine to release a reserved mutex
+ *
+ *
+ ******************************************************************************
+ *
+ *	Change History
+ *
+ *  Vn       Date    	Author         		Comment
+ *
+ *  1.0      Jan 1999  Keith Matthews        Initial version
+ *
+ */
+ DWORD Release_reserved_mutex (HANDLE32 mutex, LPTSTR mutex_name, BOOL32 release_handle_m, BOOL32 release_this_i )
+{
+	ReleaseMutex(mutex);
+        if ( (err_no=GetLastError()) != 0 )
+        {
+                ERR(ddeml,"ReleaseMutex failed - %s mutex %li\n",mutex_name,err_no);
+                HeapFree(GetProcessHeap(), 0, this_instance);
+		if ( release_handle_m )
+		{
+			ReleaseMutex(handle_mutex);
+		}
+                return DMLERR_SYS_ERROR;
+         }
+	if ( release_this_i )
+	{
+                HeapFree(GetProcessHeap(), 0, this_instance);
+	}
+	return DMLERR_NO_ERROR;
+}
+
+/******************************************************************************
+ *		IncrementInstanceId
+ *
+ *	generic routine to increment the max instance Id and allocate a new application instance
+ *
+ ******************************************************************************
+ *
+ *	Change History
+ *
+ *  Vn       Date    	Author         		Comment
+ *
+ *  1.0      Jan 1999  Keith Matthews        Initial version
+ *
+ */
+DWORD IncrementInstanceId()
+{
+    	SECURITY_ATTRIBUTES s_attrib;
+	/*  Need to set up Mutex in case it is not already present */
+	// increment handle count & get value
+	if ( !inst_count_mutex )
+	{
+		s_attrib.bInheritHandle = TRUE;
+		s_attrib.lpSecurityDescriptor = NULL;
+		s_attrib.nLength = sizeof(s_attrib);
+		inst_count_mutex = CreateMutex32W(&s_attrib,1,DDEInstanceAccess); // 1st time through
+	} else {
+		WaitForSingleObject(inst_count_mutex,1000); // subsequent calls
+		/*  FIXME  - needs refinement with popup for timeout, also is timeout interval OK */
+	}
+	if ( (err_no=GetLastError()) == ERROR_INVALID_HANDLE )
+	{
+		ERR(ddeml,"CreateMutex failed - inst_count %li\n",err_no);
+		err_no=Release_reserved_mutex (handle_mutex,"handle_mutex",0,1);
+		return DMLERR_SYS_ERROR;
+	}
+	DDE_Max_Assigned_Instance++;
+	this_instance->Instance_id = DDE_Max_Assigned_Instance;
+	if (Release_reserved_mutex(inst_count_mutex,"instance_count",1,0)) return DMLERR_SYS_ERROR;
+	return DMLERR_NO_ERROR;
+}
 
 /******************************************************************************
  *            DdeInitialize16   (DDEML.2)
@@ -178,17 +303,234 @@
  * RETURNS
  *    Success: DMLERR_NO_ERROR
  *    Failure: DMLERR_DLL_USAGE, DMLERR_INVALIDPARAMETER, DMLERR_SYS_ERROR
+ *
+ ******************************************************************************
+ *
+ *	Change History
+ *
+ *  Vn       Date    	Author         		Comment
+ *
+ *  1.0      Pre 1998  Alexandre/Len	     Initial Stub
+ *  1.1      Jan 1999  Keith Matthews        Initial (near-)complete version
+ *
  */
 UINT32 WINAPI DdeInitialize32W( LPDWORD pidInst, PFNCALLBACK32 pfnCallback,
                                 DWORD afCmd, DWORD ulRes )
 {
-    FIXME(ddeml, "(%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
+    DDE_HANDLE_ENTRY *reference_inst;
+    SECURITY_ATTRIBUTES s_attrib;
+    s_att = &s_attrib;
 
-    if(pidInst)
-      *pidInst = 0;
+//  probably not really capable of handling mutliple processes, but should handle
+//	multiple instances within one process
 
     if( ulRes )
+    {
         ERR(dde, "Reserved value not zero?  What does this mean?\n");
+        FIXME(ddeml, "(%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
+        /* trap this and no more until we know more */
+        return DMLERR_NO_ERROR;
+    }
+    if (!pfnCallback ) 
+    {
+        /* can't set up the instance with nothing to act as a callback */
+        TRACE(ddeml,"No callback provided\n");
+        return DMLERR_INVALIDPARAMETER; /* might be DMLERR_DLL_USAGE */
+     }
+
+     /* grab enough heap for one control struct - not really necessary for re-initialise
+	but allows us to use same validation routines */
+     this_instance= (DDE_HANDLE_ENTRY*)HeapAlloc( SystemHeap, 0, sizeof(DDE_HANDLE_ENTRY) );
+     if ( this_instance == NULL )
+     {
+	// catastrophe !! warn user & abort
+	ERR (ddeml,"Instance create failed - out of memory\n");
+	return DMLERR_SYS_ERROR;
+     }
+     this_instance->Next_Entry = NULL;
+     this_instance->Monitor=(afCmd|APPCLASS_MONITOR);
+
+     // messy bit, spec implies that 'Client Only' can be set in 2 different ways, catch 1 here
+
+     this_instance->Client_only=afCmd&APPCMD_CLIENTONLY;
+     this_instance->Instance_id = pidInst; // May need to add calling proc Id
+     this_instance->CallBack=*pfnCallback;
+     this_instance->Txn_count=0;
+     this_instance->Unicode = TRUE;
+     this_instance->Win16 = FALSE;
+     this_instance->Monitor_flags = afCmd & MF_MASK;
+
+     // isolate CBF flags in one go, expect this will go the way of all attempts to be clever !!
+
+     this_instance->CBF_Flags=afCmd^((afCmd&MF_MASK)|((afCmd&APPCMD_MASK)|(afCmd&APPCLASS_MASK)));
+
+     if ( ! this_instance->Client_only )
+     {
+
+	// Check for other way of setting Client-only !!
+
+	this_instance->Client_only=(this_instance->CBF_Flags&CBF_FAIL_ALLSVRXACTIONS)
+			==CBF_FAIL_ALLSVRXACTIONS;
+     }
+
+     TRACE(ddeml,"instance created - checking validity \n");
+
+    if( *pidInst == 0 ) {
+        /*  Initialisation of new Instance Identifier */
+        TRACE(ddeml,"new instance, callback %p flags %lX\n",pfnCallback,afCmd);
+	/*  Need to set up Mutex in case it is not already present */
+	s_att->bInheritHandle = TRUE;
+	s_att->lpSecurityDescriptor = NULL;
+	s_att->nLength = sizeof(s_att);
+	handle_mutex = CreateMutex32W(s_att,1,DDEHandleAccess);
+	if ( (err_no=GetLastError()) == ERROR_INVALID_HANDLE )
+	{
+		ERR(ddeml,"CreateMutex failed - handle list  %li\n",err_no);
+                HeapFree(GetProcessHeap(), 0, this_instance);
+		return DMLERR_SYS_ERROR;
+	}
+	TRACE(ddeml,"Handle Mutex created/reserved\n");
+        if (DDE_Handle_Table_Base == NULL ) 
+	{
+                /* can't be another instance in this case, assign to the base pointer */
+                DDE_Handle_Table_Base= this_instance;
+
+		// since first must force filter of XTYP_CONNECT and XTYP_WILDCONNECT for
+		//    present
+		//   -------------------------------      NOTE NOTE NOTE    --------------------------
+		//
+		//	   the manual is not clear if this condition
+		//	applies to the first call to DdeInitialize from an application, or the 
+		//	first call for a given callback !!!
+		//
+
+		this_instance->CBF_Flags=this_instance->CBF_Flags|APPCMD_FILTERINITS;
+ 		TRACE(ddeml,"First application instance detected OK\n");
+		// allocate new instance ID
+		if ((err_no = IncrementInstanceId()) ) return err_no;
+   	} else {
+                /* really need to chain the new one in to the latest here, but after checking conditions
+                such as trying to start a conversation from an application trying to monitor */
+                reference_inst =  DDE_Handle_Table_Base;
+		TRACE(ddeml,"Subsequent application instance - starting checks\n");
+                while ( reference_inst->Next_Entry != NULL ) 
+		{
+			//
+			//	This set of tests will work if application uses same instance Id
+			//	at application level once allocated - which is what manual implies
+			//	should happen. If someone tries to be 
+			//	clever (lazy ?) it will fail to pick up that later calls are for
+			//	the same application - should we trust them ?
+			//
+                        if ( this_instance->Instance_id == reference_inst->Instance_id) 
+			{
+				// Check 1 - must be same Client-only state
+
+                                if ( this_instance->Client_only != reference_inst->Client_only)
+				{
+					if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+						return DMLERR_SYS_ERROR;
+                                        return DMLERR_DLL_USAGE;
+                                }
+
+				// Check 2 - cannot use 'Monitor' with any non-monitor modes
+
+                                if ( this_instance->Monitor != reference_inst->Monitor) 
+				{
+					if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+						return DMLERR_SYS_ERROR;
+                                        return DMLERR_INVALIDPARAMETER;
+                                }
+
+				// Check 3 - must supply different callback address
+
+				if ( this_instance->CallBack == reference_inst->CallBack)
+				{
+					if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+						return DMLERR_SYS_ERROR;
+                                        return DMLERR_DLL_USAGE;
+				}
+                        }
+                        reference_inst = reference_inst->Next_Entry;
+                }
+		//  All cleared, add to chain
+
+		TRACE(ddeml,"Application Instance checks finished\n");
+                if ((err_no = IncrementInstanceId())) return err_no;
+		if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,0)) return DMLERR_SYS_ERROR;
+		reference_inst->Next_Entry = this_instance;
+        }
+	pidInst = (LPDWORD)this_instance->Instance_id;
+	TRACE(ddeml,"New application instance processing finished OK\n");
+     } else {
+        /* Reinitialisation situation   --- FIX  */
+        TRACE(ddeml,"reinitialisation of (%p,%p,0x%lx,%ld): stub\n",pidInst,pfnCallback,afCmd,ulRes);
+	WaitForSingleObject(handle_mutex,1000);
+        if ( (err_no=GetLastError()) != 0 )
+            {
+
+	     /*  FIXME  - needs refinement with popup for timeout, also is timeout interval OK */
+
+                    ERR(ddeml,"WaitForSingleObject failed - handle list %li\n",err_no);
+                    HeapFree(GetProcessHeap(), 0, this_instance);
+                    return DMLERR_SYS_ERROR;
+        }
+        if (DDE_Handle_Table_Base == NULL ) 
+	{
+		if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1)) return DMLERR_SYS_ERROR;
+        	return DMLERR_DLL_USAGE;
+ 	}
+        HeapFree(GetProcessHeap(), 0, this_instance); // finished - release heap space used as work store
+        // can't reinitialise if we have initialised nothing !!
+        reference_inst =  DDE_Handle_Table_Base;
+        /* must first check if we have been given a valid instance to re-initialise !!  how do we do that ? */
+	while ( reference_inst->Next_Entry != NULL )
+	{
+		if ( pidInst == reference_inst->Instance_id && pfnCallback == reference_inst->CallBack )
+		{
+			// Check 1 - cannot change client-only mode if set via APPCMD_CLIENTONLY
+
+			if (  reference_inst->Client_only )
+			{
+			   if  ((reference_inst->CBF_Flags & CBF_FAIL_ALLSVRXACTIONS) != CBF_FAIL_ALLSVRXACTIONS) 
+			   {
+				// i.e. Was set to Client-only and through APPCMD_CLIENTONLY
+
+				if ( ! ( afCmd & APPCMD_CLIENTONLY))
+				{
+					if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+						return DMLERR_SYS_ERROR;
+                                	return DMLERR_DLL_USAGE;
+				}
+			   }
+			}
+			// Check 2 - cannot change monitor modes
+
+                        if ( this_instance->Monitor != reference_inst->Monitor) 
+			{
+				if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+					return DMLERR_SYS_ERROR;
+                                return DMLERR_DLL_USAGE;
+                        }
+
+			// Check 3 - trying to set Client-only via APPCMD when not set so previously
+
+			if (( afCmd&APPCMD_CLIENTONLY) && ! reference_inst->Client_only )
+			{
+				if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+					return DMLERR_SYS_ERROR;
+                                return DMLERR_DLL_USAGE;
+			}
+		}
+	}
+	//		All checked - change relevant flags
+
+	reference_inst->CBF_Flags = this_instance->CBF_Flags;
+	reference_inst->Client_only = this_instance->Client_only;
+	reference_inst->Monitor_flags = this_instance->Monitor_flags;
+	if ( Release_reserved_mutex(handle_mutex,"handle_mutex",0,1))
+		return DMLERR_SYS_ERROR;
+     }
 
     return DMLERR_NO_ERROR;
 }