private string Build_SubscribeEvents_Device(string first, CodeProcessor cs, UPnPDevice device, Hashtable serviceNames)
        {
            foreach (UPnPService service in device.Services)
            {
                bool HasEvent = false;
                foreach (UPnPStateVariable sv in service.GetStateVariables())
                {
                    if (sv.SendEvent)
                    {
                        HasEvent = true;
                        break;
                    }
                }

                if (HasEvent)
                {
                    UPnPDebugObject obj = new UPnPDebugObject(service);
                    string name = (string)obj.GetField("__eventurl");
                    cs.Append(first + " if (pathlength==" + (name.Length + 1).ToString() + " && memcmp(path+1,\"" + name + "\"," + name.Length.ToString() + ")==0)" + cl);
                    cs.Append("	{" + cl);

                    cs.Append("		" + pc_methodPrefix + "TryToSubscribe(\"" + (string)serviceNames[service] + "\",TimeoutVal,URL,URLLength,session);" + cl);

                    cs.Append("	}" + cl);
                    first = "else";
                }
            }

            foreach (UPnPDevice d in device.EmbeddedDevices)
            {
                first = Build_SubscribeEvents_Device(first, cs, d, serviceNames);
            }
            return (first);
        }
        private void BuildHTTPSink_SCPD_HEAD(CodeProcessor cs, UPnPDevice device, Hashtable serviceNames)
        {
            UPnPDebugObject obj;

            foreach (UPnPService service in device.Services)
            {
                obj = new UPnPDebugObject(service);
                string SCPDURL = (string)obj.GetField("SCPDURL");
                cs.Append("	else if (header->DirectiveObjLength==" + (SCPDURL.Length + 1).ToString() + " && memcmp((header->DirectiveObj)+1,\"" + SCPDURL + "\"," + SCPDURL.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);

                cs.Append("		" + this.pc_methodLibPrefix + "WebServer_StreamHeader_Raw(session,200,\"OK\",responseHeader,1);" + cl);
                cs.Append("		" + this.pc_methodLibPrefix + "WebServer_StreamBody(session,NULL,0," + this.pc_methodLibPrefix + "AsyncSocket_MemoryOwnership_STATIC,1);" + cl);

                cs.Append("	}" + cl);
            }

            foreach (UPnPDevice d in device.EmbeddedDevices)
            {
                this.BuildHTTPSink_SCPD_HEAD(cs, d, serviceNames);
            }
        }
        private void BuildHTTPSink_SCPD(CodeProcessor cs, UPnPDevice device, Hashtable serviceNames)
        {
            UPnPDebugObject obj;

            foreach (UPnPService service in device.Services)
            {
                obj = new UPnPDebugObject(service);
                string SCPDURL = (string)obj.GetField("SCPDURL");
                cs.Append("	else if (header->DirectiveObjLength==" + (SCPDURL.Length + 1).ToString() + " && memcmp((header->DirectiveObj)+1,\"" + SCPDURL + "\"," + SCPDURL.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);
                if (this.Configuration.DynamicObjectModel)
                {
                    cs.Append("		ILibWebServer_StreamHeader_Raw(session,200,\"OK\",responseHeader,1);" + cl);
                    cs.Append("		UPnPStreamDescriptionDocument_SCPD(session,1,NULL,0,0,0,0);" + cl);

                    if (service.Actions.Count > 0)
                    {
                        cs.Append("		buffer = ILibDecompressString((unsigned char*)UPnP_ActionTable_" + serviceNames[service] + "_Impl.Reserved,UPnP_ActionTable_" + serviceNames[service] + "_Impl.ReservedXL,UPnP_ActionTable_" + serviceNames[service] + "_Impl.ReservedUXL);" + cl);
                        foreach (UPnPAction A in service.Actions)
                        {
                            string serviceIdent = DeviceObjectGenerator.GetServiceIdentifier(service);

                            serviceIdent += ("->" + A.Name);
                            cs.Append("		if (" + serviceIdent + "!=NULL){UPnPStreamDescriptionDocument_SCPD(session,0,buffer," + serviceIdent + "->Reserved," + serviceIdent + "->Reserved2,0,0);}" + cl);
                        }
                        cs.Append("		free(buffer);" + cl);
                    }
                    cs.Append("		UPnPStreamDescriptionDocument_SCPD(session,0,NULL,0,0,1,0);" + cl);
                    if (service.GetStateVariables().Length > 0)
                    {
                        cs.Append("		buffer = ILibDecompressString((unsigned char*)UPnP_StateVariableTable_" + serviceNames[service] + "_Impl.Reserved,UPnP_StateVariableTable_" + serviceNames[service] + "_Impl.ReservedXL,UPnP_StateVariableTable_" + serviceNames[service] + "_Impl.ReservedUXL);" + cl);
                        foreach (UPnPStateVariable V in service.GetStateVariables())
                        {
                            string vIdent = DeviceObjectGenerator.GetStateVariableIdentifier(V);
                            cs.Append("		if (" + vIdent + "!=NULL)" + cl);
                            cs.Append("		{" + cl);
                            cs.Append("			ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved1," + vIdent + "->Reserved1L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                            if (V.Minimum != null || V.Maximum != null)
                            {
                                cs.Append("			ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved4," + vIdent + "->Reserved4L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("			if (" + vIdent + "->MinMaxStep[0]!=NULL)" + cl);
                                cs.Append("			{" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,\"<minimum>\",9,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session," + vIdent + "->MinMaxStep[0],(int)strlen(" + vIdent + "->MinMaxStep[0]),ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,\"</minimum>\",10,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("			}" + cl);
                                cs.Append("			if (" + vIdent + "->MinMaxStep[1]!=NULL)" + cl);
                                cs.Append("			{" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,\"<maximum>\",9,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session," + vIdent + "->MinMaxStep[1],(int)strlen(" + vIdent + "->MinMaxStep[1]),ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,\"</maximum>\",10,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("			}" + cl);
                                cs.Append("			if (" + vIdent + "->MinMaxStep[2]!=NULL)" + cl);
                                cs.Append("			{" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,\"<step>\",6,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session," + vIdent + "->MinMaxStep[2],(int)strlen(" + vIdent + "->MinMaxStep[2]),ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,\"</step>\",7,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("			}" + cl);
                                cs.Append("			ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved5," + vIdent + "->Reserved5L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                            }
                            if (V.DefaultValue != null)
                            {
                                cs.Append("			if (" + vIdent + "->DefaultValue!=NULL)" + cl);
                                cs.Append("			{" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved6," + vIdent + "->Reserved6L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session," + vIdent + "->DefaultValue,(int)strlen(" + vIdent + "->DefaultValue),ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("				ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved7," + vIdent + "->Reserved7L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("			}" + cl);
                            }
                            if (V.AllowedStringValues != null)
                            {
                                cs.Append("			ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved2," + vIdent + "->Reserved2L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("			for(i=0;i<UPnP_StateVariable_AllowedValues_MAX;++i)" + cl);
                                cs.Append("			{" + cl);
                                cs.Append("				if (" + vIdent + "->AllowedValues[i]!=NULL)" + cl);
                                cs.Append("				{" + cl);
                                cs.Append("					ILibWebServer_StreamBody(session,\"<allowedValue>\",14,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("					ILibWebServer_StreamBody(session," + vIdent + "->AllowedValues[i],(int)strlen(" + vIdent + "->AllowedValues[i]),ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                                cs.Append("					ILibWebServer_StreamBody(session,\"</allowedValue>\",15,ILibAsyncSocket_MemoryOwnership_STATIC,0);" + cl);
                                cs.Append("				}" + cl);
                                cs.Append("			}" + cl);
                                cs.Append("			ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved3," + vIdent + "->Reserved3L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                            }
                            cs.Append("			ILibWebServer_StreamBody(session,buffer+" + vIdent + "->Reserved8," + vIdent + "->Reserved8L,ILibAsyncSocket_MemoryOwnership_USER,0);" + cl);
                            cs.Append("		}" + cl);
                        }
                        cs.Append("		free(buffer);" + cl);
                    }
                    cs.Append("		UPnPStreamDescriptionDocument_SCPD(session,0,NULL,0,0,0,1);" + cl);
                }
                else
                {
                    cs.Append("		buffer = " + this.pc_methodLibPrefix + "DecompressString((unsigned char*)" + pc_methodPrefix + serviceNames[service] + "Description," + pc_methodPrefix + serviceNames[service] + "DescriptionLength," + pc_methodPrefix + serviceNames[service] + "DescriptionLengthUX);" + cl);
                    cs.Append("		" + this.pc_methodLibPrefix + "WebServer_Send_Raw(session,buffer," + pc_methodPrefix + serviceNames[service] + "DescriptionLengthUX,0,1);" + cl);
                }
                cs.Append("	}" + cl);
            }

            foreach (UPnPDevice d in device.EmbeddedDevices)
            {
                this.BuildHTTPSink_SCPD(cs, d, serviceNames);
            }
        }
        private string BuildHTTPSink_CONTROL(CodeProcessor cs, UPnPDevice device, Hashtable serviceNames, string f1)
        {
            UPnPDebugObject obj;
            string first1 = f1;

            foreach (UPnPService service in device.Services)
            {
                obj = new UPnPDebugObject(service);
                string CONTROLURL = (string)obj.GetField("__controlurl");

                cs.Append("	" + first1 + " if (header->DirectiveObjLength==" + (CONTROLURL.Length + 1).ToString() + " && memcmp((header->DirectiveObj)+1,\"" + CONTROLURL + "\"," + CONTROLURL.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);
                string first2 = "";
                foreach (UPnPAction action in service.Actions)
                {
                    cs.Append("		" + first2 + " if (SOAPACTIONLength==" + action.Name.Length.ToString() + " && memcmp(SOAPACTION,\"" + action.Name + "\"," + action.Name.Length.ToString() + ")==0)" + cl);
                    cs.Append("		{" + cl);

                    cs.Append("			" + pc_methodPrefix + "Dispatch_" + (string)serviceNames[service] + "_" + action.Name + "(bodyBuffer, offset, bodyBufferLength, session);" + cl);

                    cs.Append("		}" + cl);
                    first2 = "else";
                }
                if (service.Actions.Count > 0)
                {
                    cs.Append("		else" + cl);
                    cs.Append("		{" + cl);
                }
                cs.Append("			RetVal=1;" + cl);
                if (service.Actions.Count > 0)
                {
                    cs.Append("		}" + cl);
                }

                cs.Append("	}" + cl);
                first1 = "else";

            }
            //			if (device.Services.Length>0)
            //			{
            //				cs.Append("	else"+cl);
            //				cs.Append("	{"+cl);
            //				cs.Append("		RetVal=1;"+cl);
            //				cs.Append("	}"+cl);
            //			}
            foreach (UPnPDevice d in device.EmbeddedDevices)
            {
                first1 = this.BuildHTTPSink_CONTROL(cs, d, serviceNames, first1);
            }
            return (first1);
        }
        protected bool GenerateEx(UPnPDevice device, DirectoryInfo outputDirectory, Hashtable serviceNames, ref string SampleApp)
        {
            bool BuildSampleApp = SampleApp == null ? false : true;
            ServiceGenerator.Configuration DeviceConf = (ServiceGenerator.Configuration)device.User;

            #region Initialize
            string WS;
            StreamWriter W;
            Hashtable ChoTable = new Hashtable();
            Hashtable SeqTable = new Hashtable();
            int SequenceCounter = 0;
            int ChoiceCounter = 0;

            string first = "";
            RootDevice = device;
            SortedList SL = new SortedList();
            IDictionaryEnumerator en = serviceNames.GetEnumerator();

            while (en.MoveNext())
            {
                SL[en.Value] = en.Key;
            }
            en = SL.GetEnumerator();

            if (this.SubTarget == SUBTARGETS.NONE)
            {
                UseSystem = this.Platform.ToString();
            }
            else
            {
                UseSystem = this.SubTarget.ToString();
            }

            pc_methodPrefix = ((ServiceGenerator.Configuration)device.User).Prefix;
            pc_methodLibPrefix = Configuration.prefixlib;

            if (this.Language == LANGUAGES.C)
            {
                pc_methodPrefixDef = CallingConvention + pc_methodPrefix;
                pc_classPrefix = "";
            }

            if (this.Language == LANGUAGES.CPP)
            {
                pc_methodPrefixDef = CallingConvention + ClassName + "::" + pc_methodPrefix;
                pc_classPrefix = ClassName + "::";
            }

            AllServices.Clear();
            AddAllServices(device);

            FriendlyNameTable.Clear();
            Fix(device, 0, serviceNames);

            PrivateClassDeclarations = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            PublicClassDeclarations = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            CodeProcessor cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.NewLine = this.CodeNewLine;

            cs.ClassDefinitions = PrivateClassDeclarations;
            cs.PublicClassDefinitions = PublicClassDeclarations;
            PrivateClassDeclarations.CodeTab = Indent;
            PublicClassDeclarations.CodeTab = Indent;
            cs.CodeTab = Indent;

            #endregion

            #region New Style UPnPMicroStack.h
            WS = SourceCodeRepository.GetMicroStack_H_Template(pc_methodPrefix);

            #region UPnP/1.1 Complex Types
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildComplexTypeDefinitionsAndHeaders(SL, cs, SeqTable, ChoTable, ref SequenceCounter, ref ChoiceCounter, this.pc_methodPrefix, this.pc_methodLibPrefix);
            WS = WS.Replace("//{{{ComplexTypeCode}}}", cs.ToString());
            #endregion
            #region Function Callbacks
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);

            en.Reset();
            while (en.MoveNext())
            {
                UPnPService service = (UPnPService)en.Value;

                foreach (UPnPAction action in service.Actions)
                {
                    cs.Append("	typedef void(*UPnP_ActionHandler_" + serviceNames[service] + "_" + action.Name + ") (void* upnptoken");
                    foreach (UPnPArgument args in action.Arguments)
                    {
                        if (args.Direction == "in")
                        {
                            if (args.RelatedStateVar.ComplexType == null)
                            {
                                cs.Append("," + ToCType(args.RelatedStateVar.GetNetType().FullName) + " " + args.Name);
                                if (args.RelatedStateVar.GetNetType().FullName == "System.Byte[]")
                                {
                                    cs.Append(",int _" + args.Name + "Length");
                                }
                            }
                            else
                            {
                                // Complex Type
                                cs.Append(", struct " + args.RelatedStateVar.ComplexType.Name_LOCAL + " *" + args.Name);
                            }
                        }
                    }
                    cs.Append(");" + cl);
                }
            }
            en.Reset();
            while (en.MoveNext())
            {
                UPnPService service = (UPnPService)en.Value;
                if (Configuration.EXTERN_Callbacks == true || serviceNames[service].ToString() == "DeviceSecurity")
                {
                    foreach (UPnPAction action in service.Actions)
                    {
                        if (serviceNames[service].ToString() == "DeviceSecurity")
                        {
                            cs.Append("extern void " + pc_methodLibPrefix + serviceNames[service] + "_" + action.Name + "(void* upnptoken");
                        }
                        else
                        {
                            cs.Append("extern void " + pc_methodPrefix + serviceNames[service] + "_" + action.Name + "(void* upnptoken");
                        }
                        foreach (UPnPArgument arg in action.Arguments)
                        {
                            if (arg.Direction == "in")
                            {
                                cs.Append("," + ToCType(arg.RelatedStateVar.GetNetType().ToString()) + " " + arg.Name);
                                if (arg.RelatedStateVar.GetNetType().FullName == "System.Byte[]")
                                {
                                    cs.Append(",int _" + arg.Name + "Length");
                                }
                            }
                        }
                        cs.Append(");" + cl);
                    }
                }
            }
            if (Configuration.EXTERN_Callbacks == false)
            {
                cs.Comment("UPnP Set Function Pointers Methods");
                cs.Append("extern void (*" + pc_methodPrefixDef + "FP_PresentationPage) (void* upnptoken,struct packetheader *packet);" + cl);
                BuildFunctionPointerHeaders(cs, device, serviceNames);
                cs.Append(cl);
            }
            else
            {
                cs.Append("extern void " + pc_methodPrefix + "PresentationRequest(void* upnptoken, struct packetheader *packet);" + cl);
            }
            WS = WS.Replace("//{{{UPnP_Set_Function_Pointer_Methods}}}", cs.ToString());
            #endregion
            #region Invocation Response Methods
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);

            cs.Comment("Invocation Response Methods");
            cs.Append("void " + pc_methodPrefixDef + "Response_Error(const UPnPSessionToken UPnPToken, const int ErrorCode, const char* ErrorMsg);" + cl);
            cs.Append("void " + pc_methodPrefixDef + "ResponseGeneric(const UPnPSessionToken UPnPToken,const char* ServiceURI,const char* MethodName,const char* Params);" + cl);
            if (ServiceGenerator.ServiceConfiguration.HasFragmentedActions(device))
            {
                cs.Append("int " + pc_methodPrefixDef + "AsyncResponse_START(const UPnPSessionToken UPnPToken, const char* actionName, const char* serviceUrnWithVersion);" + cl);
                cs.Append("int " + pc_methodPrefixDef + "AsyncResponse_DONE(const UPnPSessionToken UPnPToken, const char* actionName);" + cl);
                cs.Append("int " + pc_methodPrefixDef + "AsyncResponse_OUT(const UPnPSessionToken UPnPToken, const char* outArgName, const char* bytes, const int byteLength, enum ILibAsyncSocket_MemoryOwnership bytesMemoryOwnership,const int startArg, const int endArg);" + cl);
            }
            BuildUPnPResponseHeaders(cs, device, serviceNames);
            WS = WS.Replace("//{{{Invocation_Response_Methods}}}", cs.ToString());

            #endregion
            #region Eventing Methods
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Comment("State Variable Eventing Methods");
            BuildStateVariableHeaders(cs, device, serviceNames);
            WS = WS.Replace("//{{{Eventing_Methods}}}", cs.ToString());
            #endregion
            #region Multicast Eventing Methods
            if (device.ArchitectureVersion != "1.0")
            {
                cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                cs.Comment("State Variable Multicast-Eventing Methods");
                BuildMulticastStateVariableHeaders(cs, device, serviceNames);
                WS = WS.Replace("//{{{MulticastEventing_Methods}}}", cs.ToString());
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_MulticastEventing}}}", "//{{{END_MulticastEventing}}}", WS);
                WS = BuildMulticastStateVariableHeaders2(WS, device, serviceNames);
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_MulticastEventing_Specific}}}", "//{{{END_MulticastEventing_Specific}}}", WS);
            }
            else
            {
                WS = WS.Replace("//{{{MulticastEventing_Methods}}}", "");
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_MulticastEventing}}}", "//{{{END_MulticastEventing}}}", WS);
            }
            #endregion

            #region CreateMicroStack Definition
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("UPnPMicroStackToken UPnPCreateMicroStack(void *Chain, ");
            BuildCreateMicroStackDefinition(cs, device, 1);
            cs.Append("const char* UDN, const char* SerialNumber, const int NotifyCycleSeconds, const unsigned short PortNum);" + cl);
            WS = WS.Replace("//{{{CreateMicroStackHeader}}}", cs.ToString());
            #endregion

            #region Device Object Model
            if (this.Configuration.DynamicObjectModel)
            {
                WS = WS.Replace("//{{{ObjectDefintions}}}", DeviceObjectGenerator.GetDeviceObjectsString(device));
                WS = WS.Replace("//{{{GetConfiguration}}}", "struct UPnP_Device_" + device.User2.ToString() + "* UPnPGetConfiguration();" + cl);
            }
            else
            {
                WS = WS.Replace("//{{{ObjectDefintions}}}", "");
                WS = WS.Replace("//{{{GetConfiguration}}}", "");
            }
            #endregion

            #region Prefixes
            WS = WS.Replace("UPnP", this.pc_methodPrefix);
            WS = WS.Replace("ILib", this.pc_methodLibPrefix);
            #endregion

            #region Write to disk

            W = File.CreateText(outputDirectory.FullName + "\\" + pc_methodPrefix + "MicroStack.h");

            W.Write(WS);
            W.Close();
            #endregion
            #endregion

            #region New Style UPnPMicroStack.c
            WS = SourceCodeRepository.GetMicroStack_C_Template(pc_methodPrefix);

            #region Set Function Pointers
            if (Configuration.EXTERN_Callbacks == false)
            {
                cs.Comment("UPnP Set Function Pointers Methods");
                string staticdef = "";
                if (this.Language == LANGUAGES.CPP) staticdef = "static ";
                cs.Append("void (*" + pc_methodPrefixDef + "FP_PresentationPage) (void* upnptoken,struct packetheader *packet);" + cl);
                cs.PublicClassDefinitions.Append(staticdef + "void (*" + pc_methodPrefix + "FP_PresentationPage) (void* upnptoken,struct packetheader *packet);" + cl);
                BuildFunctionPointers(cs, device, serviceNames);
                cs.Append(cl);
                WS = WS.Replace("//{{{FunctionPointers}}}", cs.ToString());
            }
            else
            {
                WS = WS.Replace("//{{{FunctionPointers}}}", "");
            }

            #endregion
            #region Build and Compress Device Description
            //Compress Device Description
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);

            BuildDeviceDescription(cs, device);
            BuildServiceDescriptions(cs, device, serviceNames);

            WS = WS.Replace("//{{{CompressedDescriptionDocs}}}", cs.ToString());
            #endregion
            #region Object Model
            if (this.Configuration.DynamicObjectModel)
            {
                WS = WS.Replace("//{{{ObjectDefintions}}}", DeviceObjectGenerator.GetPopulatedDeviceObjectsString(device));
                WS = DeviceObjectGenerator.BuildDeviceDescriptionStreamer(device, WS);
                WS = SourceCodeRepository.RemoveTag("//{{{Device_Object_Model_BEGIN}}}", "//{{{Device_Object_Model_END}}}", WS);
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{Device_Default_Model_BEGIN}}}", "//{{{Device_Default_Model_END}}}", WS);
                cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                cs.Append("struct UPnP_Device_" + device.User2.ToString() + "* UPnPGetConfiguration()" + cl);
                cs.Append("{" + cl);
                cs.Append("	return(&(" + DeviceObjectGenerator.GetDeviceIdentifier(device) + "));" + cl);
                cs.Append("}" + cl);
                WS = WS.Replace("//{{{GetConfiguration}}}", cs.ToString());
            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{Device_Object_Model_BEGIN}}}", "//{{{Device_Object_Model_END}}}", WS);
                WS = SourceCodeRepository.RemoveTag("//{{{Device_Default_Model_BEGIN}}}", "//{{{Device_Default_Model_END}}}", WS);
                WS = WS.Replace("//{{{GetConfiguration}}}", "");
            }
            #endregion

            #region FragmentedResponseSystem
            if (ServiceGenerator.ServiceConfiguration.HasFragmentedActions(device))
            {
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_FragmentedResponseSystem}}}", "//{{{END_FragmentedResponseSystem}}}", WS);
            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_FragmentedResponseSystem}}}", "//{{{END_FragmentedResponseSystem}}}", WS);
            }
            #endregion

            #region CreateMicroStackDefinition
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("UPnPMicroStackToken UPnPCreateMicroStack(void *Chain, ");
            BuildCreateMicroStackDefinition(cs, device, 1);
            cs.Append("const char* UDN, const char* SerialNumber, const int NotifyCycleSeconds, const unsigned short PortNum)" + cl);
            WS = WS.Replace("//{{{CreateMicroStackDefinition}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("	RetVal->DeviceDescriptionLength = snprintf(RetVal->DeviceDescription, len, DDT");
            if (device.ArchitectureVersion != "1.0")
            {
                cs.Append(", RetVal->ConfigID");
            }
            BuildCreateMicroStackDefinition_sprintf(cs, device, 1);
            cs.Append(");" + cl);
            WS = WS.Replace("//{{{CreateMicroStack_sprintf}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("	len = 10 + UPnPDeviceDescriptionTemplateLengthUX");
            int nd = BuildCreateMicroStackDefinition_Malloc(cs, device, 1);
            cs.Append(" + (((int)strlen(RetVal->Serial) + (int)strlen(RetVal->UUID)) * " + nd.ToString() + ");" + cl);
            cs.Append("	if ((RetVal->DeviceDescription = (char*)malloc(len)) == NULL) ILIBCRITICALEXIT(254);" + cl);

            WS = WS.Replace("//{{{DeviceDescriptionMalloc}}}", cs.ToString());

            if (nd == 1)
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_EmbeddedDevice>0}}}", "//{{{END_EmbeddedDevices>0}}}", WS);
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_EmbeddedDevices=0}}}", "//{{{END_EmbeddedDevices=0}}}", WS);
            }
            else
            {
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_EmbeddedDevice>0}}}", "//{{{END_EmbeddedDevices>0}}}", WS);
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_EmbeddedDevices=0}}}", "//{{{END_EmbeddedDevices=0}}}", WS);
            }
            #endregion
            #region CreateMicroStack  -->  Object Meta Data
            if (Configuration.DynamicObjectModel)
            {
                cs = new CodeProcessor(new StringBuilder(), false);
                BuildObjectMetaData(cs, device, 1);
                WS = WS.Replace("//{{{ObjectModel_MetaData}}}", cs.ToString());
            }
            else
            {
                WS = WS.Replace("//{{{ObjectModel_MetaData}}}", "");
            }
            #endregion

            #region Presentation Page Support
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);

            if (DeviceConf.AdvertisesPresentationPage)
            {
                cs.Append("/* Presentation Page Support */" + cl);
                cs.Append("if (header->DirectiveObjLength>=4 && memcmp(header->DirectiveObj,\"/web\",4)==0)" + cl);
                cs.Append("{" + cl);
                if (Configuration.EXTERN_Callbacks)
                {
                    cs.Append("	UPnPPresentationRequest((void*)session,header);" + cl);
                }
                else
                {
                    cs.Append("	UPnPFP_PresentationPage((void*)session,header);" + cl);
                }
                cs.Append("}" + cl);
                cs.Append("else ");
            }

            WS = WS.Replace("//{{{PRESENTATIONPAGE}}}", cs.ToString());
            #endregion

            #region #define vs method definition, on SSDP related stuff (Embedded Devices)
            if (this.GetNumberOfTotalEmbeddedDevices(device) == 0)
            {
                // No Embedded Devices
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_EmbeddedDevices=0}}}", "//{{{END_EmbeddedDevices=0}}}", WS);
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_EmbeddedDevices>0}}}", "//{{{END_EmbeddedDevices>0}}}", WS);
            }
            else
            {
                // There are Embedded Devices
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_EmbeddedDevices=0}}}", "//{{{END_EmbeddedDevices=0}}}", WS);
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_EmbeddedDevices>0}}}", "//{{{END_EmbeddedDevices>0}}}", WS);
            }
            #endregion

            #region ssdp:all
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildSSDPALL_Response(device, cs, 0);
            WS = WS.Replace("//{{{SSDP:ALL}}}", cs.ToString());
            #endregion
            #region ssdp:other

            if (DoesDeviceHaveAnyNonVersionOneComponents(device))
            {
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_VERSION>1}}}", "//{{{END_VERSION>1}}}", WS);
            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_VERSION>1}}}", "//{{{END_VERSION>1}}}", WS);
            }
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildMSEARCHHandler_device(device, cs, 0);
            WS = WS.Replace("//{{{SSDP:OTHER}}}", cs.ToString());
            #endregion
            #region FragmentedSendNotify Case statements
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("					case 1:" + cl);
            cs.Append("                     " + this.pc_methodPrefix + "BuildSendSsdpNotifyPacket(FNS->upnp->NOTIFY_SEND_socks[i], FNS->upnp, (struct sockaddr*)&(FNS->upnp->AddressListV4[i]), 0, \"::upnp:rootdevice\", \"upnp:rootdevice\", \"\");" + cl);
            cs.Append("                     break;" + cl);
            BuildFragmentedNotify_CaseStatement(cs, device, 2, 0, false);
            WS = WS.Replace("//{{{FragmentedSendNotifyCaseStatements}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("					case 1:" + cl);
            cs.Append("						" + this.pc_methodPrefix + "BuildSendSsdpNotifyPacket(FNS->upnp->NOTIFY_SEND_socks6[i], FNS->upnp, (struct sockaddr*)&(FNS->upnp->AddressListV6[i]), 0, \"::upnp:rootdevice\", \"upnp:rootdevice\", \"\");" + cl);
            cs.Append("						break;" + cl);
            BuildFragmentedNotify_CaseStatement(cs, device, 2, 0, true);
            WS = WS.Replace("//{{{FragmentedSendNotifyV6CaseStatements}}}", cs.ToString());
            #endregion

            #region SendNotify "For statement"
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("					" + pc_methodPrefix + "BuildSendSsdpNotifyPacket(upnp->NOTIFY_SEND_socks[i], upnp, (struct sockaddr*)&(upnp->AddressListV4[i]), 0, \"::upnp:rootdevice\", \"upnp:rootdevice\", \"\");" + cl);
            BuildNotifyPackets_Device(cs, device, 0, false);
            WS = WS.Replace("//{{{SendNotifyForStatement}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("					" + pc_methodPrefix + "BuildSendSsdpNotifyPacket(upnp->NOTIFY_SEND_socks6[i], upnp, (struct sockaddr*)&(upnp->AddressListV6[i]), 0, \"::upnp:rootdevice\", \"upnp:rootdevice\", \"\");" + cl);
            BuildNotifyPackets_Device(cs, device, 0, true);
            WS = WS.Replace("//{{{SendNotifyV6ForStatement}}}", cs.ToString());
            WS = WS.Replace("!NUMPACKETS!", this.CountPackets(device).ToString());
            #endregion

            #region SendByeBye "For statement"
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("			      " + pc_methodPrefix + "BuildSendSsdpByeByePacket(upnp->NOTIFY_SEND_socks[i], upnp, (struct sockaddr*)&(upnp->MulticastAddrV4), UPNP_MCASTv4_GROUP, \"::upnp:rootdevice\", \"upnp:rootdevice\", \"\", 0);" + cl);
            BuildByeByePackets_Device(cs, device, 0, false);
            WS = WS.Replace("//{{{SendByeByeForStatement}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            cs.Append("			      " + pc_methodPrefix + "BuildSendSsdpByeByePacket(upnp->NOTIFY_SEND_socks6[i], upnp, t1, t2, \"::upnp:rootdevice\", \"upnp:rootdevice\", \"\", 0);" + cl);
            BuildByeByePackets_Device(cs, device, 0, true);
            WS = WS.Replace("//{{{SendByeByeV6ForStatement}}}", cs.ToString());
            #endregion

            #region Device Icon
            if (device.Icon != null)
            {
                WS = SourceCodeRepository.RemoveTag("//{{{DeviceIcon_Begin}}}", "//{{{DeviceIcon_End}}}", WS);
                string iconString;
                MemoryStream ms = new MemoryStream();

                device.Icon.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                HTTPMessage r;
                if (Configuration.HTTP_1dot1)
                {
                    r = new HTTPMessage("1.1");
                }
                else
                {
                    r = new HTTPMessage("1.0");
                }
                r.StatusCode = 200;
                r.StatusData = "OK";
                r.ContentType = "image/png";
                r.BodyBuffer = ms.ToArray();

                // Small PNG
                DeviceObjectGenerator.InjectBytes(out iconString, r.RawPacket, this.CodeNewLine, false);
                WS = WS.Replace("{{{IconLength_SMPNG}}}", r.RawPacket.Length.ToString());
                WS = WS.Replace("{{{IconLength_HEAD_SMPNG}}}", (r.RawPacket.Length - r.BodyBuffer.Length).ToString());
                WS = WS.Replace("{{{ICON_SMPNG}}}", iconString);

                // Small JPG
                ms = new MemoryStream();
                device.Icon.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                r.ContentType = "image/jpg";
                r.BodyBuffer = ms.ToArray();
                DeviceObjectGenerator.InjectBytes(out iconString, r.RawPacket, this.CodeNewLine, false);
                WS = WS.Replace("{{{IconLength_SMJPG}}}", r.RawPacket.Length.ToString());
                WS = WS.Replace("{{{IconLength_HEAD_SMJPG}}}", (r.RawPacket.Length - r.BodyBuffer.Length).ToString());
                WS = WS.Replace("{{{ICON_SMJPG}}}", iconString);

                if (device.Icon2 != null)
                {
                    // Large PNG
                    ms = new MemoryStream();
                    device.Icon2.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
                    r.ContentType = "image/png";
                    r.BodyBuffer = ms.ToArray();
                    DeviceObjectGenerator.InjectBytes(out iconString, r.RawPacket, this.CodeNewLine, false);
                    WS = WS.Replace("{{{IconLength_LGPNG}}}", r.RawPacket.Length.ToString());
                    WS = WS.Replace("{{{IconLength_HEAD_LGPNG}}}", (r.RawPacket.Length - r.BodyBuffer.Length).ToString());
                    WS = WS.Replace("{{{ICON_LGPNG}}}", iconString);

                    // Large JPG
                    ms = new MemoryStream();
                    device.Icon2.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                    r.ContentType = "image/jpg";
                    r.BodyBuffer = ms.ToArray();
                    DeviceObjectGenerator.InjectBytes(out iconString, r.RawPacket, this.CodeNewLine, false);
                    WS = WS.Replace("{{{IconLength_LGJPG}}}", r.RawPacket.Length.ToString());
                    WS = WS.Replace("{{{IconLength_HEAD_LGJPG}}}", (r.RawPacket.Length - r.BodyBuffer.Length).ToString());
                    WS = WS.Replace("{{{ICON_LGJPG}}}", iconString);
                }

            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{DeviceIcon_Begin}}}", "//{{{DeviceIcon_End}}}", WS);
            }
            #endregion

            #region Dispatch Methods
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            Build_DispatchMethods(cs, serviceNames);
            WS = WS.Replace("//{{{DispatchMethods}}}", cs.ToString());
            #endregion
            #region Dispatch Controller
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            if (BuildHTTPSink_CONTROL(cs, device, serviceNames, "") != "")
            {
                cs.Append("	else" + cl);
                cs.Append("	{" + cl);
                cs.Append("		RetVal=1;" + cl);
                cs.Append("	}" + cl);
            }
            else
            {
                cs.Append("		RetVal=1;" + cl);
            }
            WS = WS.Replace("//{{{DispatchControl}}}", cs.ToString());
            #endregion

            #region Invocation Response Methods
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildUPnPResponse(cs, device, serviceNames);
            WS = WS.Replace("//{{{InvokeResponseMethods}}}", cs.ToString());
            #endregion
            #region GetInitialEventBody
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildEventHelpers_InitialEvent(cs, serviceNames);
            WS = WS.Replace("//{{{InitialEventBody}}}", cs.ToString());
            #endregion
            #region Multicast Events
            if (device.ArchitectureVersion != "1.0")
            {
                cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                BuildMulticastSoapEvents(cs, device, serviceNames);
                WS = WS.Replace("//{{{SetStateMethods}}}", "//{{{SetStateMethods}}}\r\n" + cs.ToString());

                WS = BuildMulticastSoapEventsProcessor(WS, device, serviceNames);

                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_CHECK_MULTICASTVARIABLE}}}", "//{{{END_CHECK_MULTICASTVARIABLE}}}", WS);
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_MulticastEventing}}}", "//{{{END_MulticastEventing}}}", WS);
                WS = WS.Replace("{{{VARDEFS}}}", "");
            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_MulticastEventing}}}", "//{{{END_MulticastEventing}}}", WS);
            }
            #endregion
            #region SetState Methods
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildSoapEvents(cs, device, serviceNames);
            WS = WS.Replace("//{{{SetStateMethods}}}", cs.ToString());
            #endregion

            #region UnSubscribeDispatcher
            string packet = "HTTP/!HTTPVERSION! %d %s\\r\\nContent-Length: 0\\r\\n\\r\\n";

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            first = "";
            en.Reset();
            while (en.MoveNext())
            {
                UPnPService service = (UPnPService)en.Value;
                UPnPDebugObject obj = new UPnPDebugObject(service);
                string name = (string)obj.GetField("__eventurl");

                cs.Append("	" + first + "if (header->DirectiveObjLength==" + (name.Length + 1).ToString() + " && memcmp(header->DirectiveObj + 1,\"" + name + "\"," + name.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);

                cs.Append("		Info = " + pc_methodPrefix + "RemoveSubscriberInfo(&(((struct " + pc_methodPrefix + "DataObject*)session->User)->HeadSubscriberPtr_" + (string)en.Key + "),&(((struct " + pc_methodPrefix + "DataObject*)session->User)->NumberOfSubscribers_" + (string)en.Key + "),SID,SIDLength);" + cl);

                cs.Append("		if (Info != NULL)" + cl);
                cs.Append("		{" + cl);
                cs.Append("			--Info->RefCount;" + cl);
                cs.Append("			if (Info->RefCount == 0)" + cl);
                cs.Append("			{" + cl);
                cs.Append("				" + pc_methodPrefix + "DestructSubscriberInfo(Info);" + cl);
                cs.Append("			}" + cl);
                cs.Append("			packetlength = snprintf(packet, 50, \"" + packet + "\", 200, \"OK\");" + cl);

                cs.Append("			" + this.pc_methodLibPrefix + "WebServer_Send_Raw(session, packet, packetlength, 0, 1);" + cl);

                cs.Append("		}" + cl);
                cs.Append("		else" + cl);
                cs.Append("		{" + cl);
                cs.Append("			packetlength = snprintf(packet, 50, \"" + packet + "\", 412, \"Invalid SID\");" + cl);

                cs.Append("			" + this.pc_methodLibPrefix + "WebServer_Send_Raw(session, packet, packetlength, 0, 1);" + cl);

                cs.Append("		}" + cl);
                cs.Append("	}" + cl);
                first = "else ";
            }
            WS = WS.Replace("//{{{UnSubscribeDispatcher}}}", cs.ToString());
            #endregion
            #region SubscribeDispatcher
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            first = Build_SubscribeEvents_Device("", cs, device, serviceNames);
            if (first != "")
            {
                cs.Append("	else" + cl);
                cs.Append("	{" + cl);

                cs.Append("		" + this.pc_methodLibPrefix + "WebServer_Send_Raw(session,\"HTTP/1.1 412 Invalid Service Name\\r\\nContent-Length: 0\\r\\n\\r\\n\",56,1,1);" + cl);

                cs.Append("	}" + cl);
            }
            else
            {

                cs.Append("	" + this.pc_methodLibPrefix + "WebServer_Send_Raw(session,\"HTTP/1.1 412 Invalid Service Name\\r\\nContent-Length: 0\\r\\n\\r\\n\",56,1,1);" + cl);

            }
            WS = WS.Replace("//{{{SubscribeEventsDispatcher}}}", cs.ToString());
            #endregion
            #region Maximum Subscription Timeout
            WS = WS.Replace("{{{UPnP_MAX_SUBSCRIPTION_TIMEOUT}}}", ((ServiceGenerator.Configuration)device.User).MaxSubscriptionTimeout.ToString());
            #endregion

            #region State Variables
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                UPnPService s = (UPnPService)en.Value;

                foreach (UPnPStateVariable v in s.GetStateVariables())
                {
                    if (v.SendEvent)
                    {
                        cs.Append("	char* " + name + "_" + v.Name + ";" + cl);
                    }
                    if (v.MulticastEvent)
                    {
                        cs.Append("	int " + name + "_" + v.Name + "_SEQ;" + cl);
                    }
                }
            }
            WS = WS.Replace("//{{{StateVariables}}}", cs.ToString());
            #endregion
            #region Subscriber Head Pointer
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                cs.Append("	struct SubscriberInfo *HeadSubscriberPtr_" + name + ";" + cl);
                cs.Append("	int NumberOfSubscribers_" + name + ";" + cl);
            }
            WS = WS.Replace("//{{{HeadSubscriberPointers}}}", cs.ToString());
            #endregion
            #region UPnPExpireSubscriberInfo
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            first = "";
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                cs.Append("	" + first + "if (d->HeadSubscriberPtr_" + name + "==t)" + cl);
                cs.Append("	{" + cl);
                cs.Append("		--(d->NumberOfSubscribers_" + name + ");" + cl);
                cs.Append("	}" + cl);
                first = "else ";
            }
            WS = WS.Replace("//{{{UPnPExpireSubscriberInfo1}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            first = "";
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                cs.Append("	" + first + "if (d->HeadSubscriberPtr_" + name + "==info)" + cl);
                cs.Append("	{" + cl);
                cs.Append("		d->HeadSubscriberPtr_" + name + " = info->Next;" + cl);
                cs.Append("		if (info->Next!=NULL)" + cl);
                cs.Append("		{" + cl);
                cs.Append("			info->Next->Previous = NULL;" + cl);
                cs.Append("		}" + cl);
                cs.Append("	}" + cl);
                first = "else ";
            }
            cs.Append("	" + first + cl);
            if (first != "")
            {
                cs.Append("	{" + cl);
            }
            cs.Append("		// Error" + cl);
            cs.Append("		return;" + cl);
            if (first != "")
            {
                cs.Append("	}" + cl);
            }
            WS = WS.Replace("//{{{UPnPExpireSubscriberInfo2}}}", cs.ToString());
            #endregion
            #region TryToSubscribe HeadPointer Initializer
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                cs.Append("	if (strncmp(ServiceName,\"" + name + "\"," + name.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);

                cs.Append("		TotalSubscribers = &(dataObject->NumberOfSubscribers_" + name + ");" + cl);
                cs.Append("		HeadPtr = &(dataObject->HeadSubscriberPtr_" + name + ");" + cl);

                cs.Append("	}" + cl);
            }
            WS = WS.Replace("//{{{SubscribeHeadPointerInitializer}}}", cs.ToString());
            #endregion
            #region TryToSubscribe Initial Event
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            first = "";
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                UPnPService s = (UPnPService)en.Value;
                bool HasEvents = false;
                foreach (UPnPStateVariable v in s.GetStateVariables())
                {
                    if (v.SendEvent)
                    {
                        HasEvents = true;
                        break;
                    }
                }

                if (HasEvents)
                {
                    cs.Append("	" + first + "if (strcmp(ServiceName,\"" + name + "\")==0)" + cl);
                    cs.Append("	{" + cl);
                    cs.Append("		UPnPGetInitialEventBody_" + name + "(dataObject,&packetbody,&packetbodyLength);" + cl);
                    cs.Append("	}" + cl);
                    first = "else ";
                }
            }
            WS = WS.Replace("//{{{TryToSubscribe_InitialEvent}}}", cs.ToString());
            #endregion
            #region Subscription Renewal HeadPointer Initializer
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            first = "";
            en.Reset();
            while (en.MoveNext())
            {
                UPnPService service = (UPnPService)en.Value;
                UPnPDebugObject obj = new UPnPDebugObject(service);
                string name = (string)obj.GetField("__eventurl");
                string sname = (string)en.Key;

                cs.Append(first + " if (pathlength==" + (name.Length + 1).ToString() + " && memcmp(path+1,\"" + name + "\"," + name.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);

                cs.Append("		info = ((struct " + this.pc_methodPrefix + "DataObject*)ReaderObject->User)->HeadSubscriberPtr_" + sname + ";" + cl);

                cs.Append("	}" + cl);
                first = "else";
            }
            WS = WS.Replace("//{{{RenewHeadInitializer}}}", cs.ToString());
            #endregion
            #region SendEvent HeadPointer Initializer
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en.Reset();
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                cs.Append("	if (strncmp(eventname,\"" + name + "\"," + name.Length.ToString() + ")==0)" + cl);
                cs.Append("	{" + cl);
                cs.Append("		info = UPnPObject->HeadSubscriberPtr_" + name + ";" + cl);
                cs.Append("	}" + cl);
            }
            WS = WS.Replace("//{{{SendEventHeadPointerInitializer}}}", cs.ToString());
            #endregion

            #region HeadDispatcher
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildHTTPSink_SCPD_HEAD(cs, device, serviceNames);
            WS = WS.Replace("//{{{HeadDispatcher}}}", cs.ToString());
            #endregion
            #region GetDispatcher
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildHTTPSink_SCPD(cs, device, serviceNames);
            WS = WS.Replace("//{{{GetDispatcher}}}", cs.ToString());

            if (DeviceObjectGenerator.CalculateMaxAllowedValues(device, 0) != 0)
            {
                WS = SourceCodeRepository.RemoveTag("//{{{HASALLOWEDVALUES_BEGIN}}}", "//{{{HASALLOWEDVALUES_END}}}", WS);
            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{HASALLOWEDVALUES_BEGIN}}}", "//{{{HASALLOWEDVALUES_END}}}", WS);
            }
            #endregion

            #region DestroyMicroStack
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            while (en.MoveNext())
            {
                string name = (string)en.Key;
                UPnPService s = (UPnPService)en.Value;

                foreach (UPnPStateVariable v in s.GetStateVariables())
                {
                    if (v.SendEvent && v.GetNetType() != typeof(bool))
                    {
                        cs.Append("	free(upnp->" + name + "_" + v.Name + ");" + cl);
                    }
                }
            }
            WS = WS.Replace("//{{{UPnPDestroyMicroStack_FreeEventResources}}}", cs.ToString());

            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            en = SL.GetEnumerator();
            while (en.MoveNext())
            {
                string name = (string)en.Key;

                cs.Append("	sinfo = upnp->HeadSubscriberPtr_" + name + ";" + cl);
                cs.Append("	while(sinfo!=NULL)" + cl);
                cs.Append("	{" + cl);
                cs.Append("		sinfo2 = sinfo->Next;" + cl);
                cs.Append("		UPnPDestructSubscriberInfo(sinfo);" + cl);
                cs.Append("		sinfo = sinfo2;" + cl);
                cs.Append("	}" + cl);
            }
            WS = WS.Replace("//{{{UPnPDestroyMicroStack_DestructSubscriber}}}", cs.ToString());

            #endregion

            #region UPnP/1.1 Complex Types
            cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
            BuildComplexTypeParser(SeqTable, ChoTable, cs, SL, this.pc_methodPrefix, this.pc_methodLibPrefix);
            CPEmbeddedCGenerator.BuildComplexTypeSerializer(SeqTable, ChoTable, cs, SL, this.pc_methodPrefix, this.pc_methodLibPrefix);
            WS = WS.Replace("//{{{ComplexTypeCode}}}", cs.ToString());
            #endregion

            #region HTTP Version
            if (!Configuration.HTTP_1dot1)
            {
                WS = WS.Replace("!HTTPVERSION!", "1.0");
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}}", "//{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}}", WS);
            }
            else
            {
                WS = WS.Replace("!HTTPVERSION!", "1.1");
                WS = SourceCodeRepository.RemoveTag("//{{{ REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT--> }}}", "//{{{ <--REMOVE_THIS_FOR_HTTP/1.0_ONLY_SUPPORT }}}", WS);
            }
            WS = WS.Replace("!MICROSTACKVERSION!", this.UseVersion);
            #endregion
            #region UPnP Specific Version
            if (device.ArchitectureVersion == "1.0")
            {
                // UPnP/1.0
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_UPnP/1.1_Specific}}}", "//{{{END_UPnP/1.1_Specific}}}", WS);
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_UPnP/1.0_Specific}}}", "//{{{END_UPnP/1.0_Specific}}}", WS);
                WS = WS.Replace("!UPNPVERSION!", "1.0");
            }
            else
            {
                // UPnP/1.1
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_UPnP/1.0_Specific}}}", "//{{{END_UPnP/1.0_Specific}}}", WS);
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_UPnP/1.1_Specific}}}", "//{{{END_UPnP/1.1_Specific}}}", WS);
                WS = WS.Replace("!UPNPVERSION!", "1.1");
            }
            #endregion

            #region Remove Event Processing if no evented State Variables
            if (DeviceHasEvents(device))
            {
                WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_EVENTPROCESSING}}}", "//{{{END_EVENTPROCESSING}}}", WS);
            }
            else
            {
                WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_EVENTPROCESSING}}}", "//{{{END_EVENTPROCESSING}}}", WS);
            }
            #endregion

            #region Prefixes
            WS = FixPrefix_DeviceService(device, WS);
            WS = WS.Replace("UPnP/", "upnp/");
            WS = WS.Replace("UPnPError", "_upnperror_");
            WS = WS.Replace(" UPnP ", " _upnp_ ");
            WS = WS.Replace("UPnP", this.pc_methodPrefix);
            WS = WS.Replace("ILib", this.pc_methodLibPrefix);
            WS = WS.Replace("_upnperror_", "UPnPError");
            WS = WS.Replace("upnp/", "UPnP/");
            WS = WS.Replace(" _upnp_ ", " UPnP ");
            WS = FixPrefix2_DeviceService(device, WS);
            #endregion

            #region Reformat String
            WS = CodeProcessor.ProcessCode(WS, Indent);
            #endregion

            #region Write to disk
            if (this.Language == LANGUAGES.C)
            {
                W = File.CreateText(outputDirectory.FullName + "\\" + pc_methodPrefix + "MicroStack.c");
            }
            else
            {
                W = File.CreateText(outputDirectory.FullName + "\\" + pc_methodPrefix + "MicroStack.cpp");
            }
            W.Write(WS);
            W.Close();
            #endregion

            #endregion

            #region Sample Application
            if (BuildSampleApp)
            {
                WS = SampleApp;

                #region Display Message
                WS = WS.Replace("{{{INITSTRING}}}", (string)FriendlyNameTable[device] + " {{{INITSTRING}}}");
                #endregion

                #region ImplementationMethods
                if (!Configuration.BareBonesSample)
                {
                    cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                    BuildMainUserCode(cs, device, serviceNames);
                    WS = WS.Replace("//{{{DEVICE_INVOCATION_DISPATCH}}}", "//{{{DEVICE_INVOCATION_DISPATCH}}}" + cl + cs.ToString());
                }
                #endregion
                #region ImplementationMethods: Function Pointer Initialization
                if (!Configuration.BareBonesSample)
                {
                    if (Configuration.EXTERN_Callbacks == false)
                    {
                        cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                        cs.ident = 1;

                        if (DeviceConf.AdvertisesPresentationPage)
                        {
                            cs.Append(pc_methodPrefix + "FP_PresentationPage=&" + pc_methodPrefix + "PresentationRequest;" + cl);
                        }
                        BuildMain_SetFunctionPointers(cs, device, serviceNames);
                        WS = WS.Replace("//{{{INVOCATION_FP}}}", "//{{{INVOCATION_FP}}}" + cl + cs.ToString());
                    }
                }
                #endregion

                #region PresentationRequest
                if (DeviceConf.AdvertisesPresentationPage)
                {
                    cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                    cs.Append("void UPnPPresentationRequest(void* upnptoken, struct packetheader *packet)" + cl);
                    cs.Append("{" + cl);
                    cs.Append("	printf(\"UPnP Presentation Request: %s %s\\r\\n\", packet->Directive,packet->DirectiveObj);" + cl);
                    cs.Append(cl);
                    cs.Append("	/* TODO: Add Web Response Code Here... */" + cl);
                    cs.Append("	printf(\"HOST: %x\\r\\n\",UPnPGetLocalInterfaceToHost(upnptoken));" + cl);
                    cs.Append(cl);
                    cs.Append("	ILibWebServer_Send_Raw((struct ILibWebServer_Session *)upnptoken, \"HTTP/1.1 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\" , 38 , 1, 1);" + cl);
                    cs.Append("}" + cl);

                    WS = WS.Replace("//{{{PresentationRequest}}}", "//{{{PresentationRequest}}}" + cl + cs.ToString());
                }
                #endregion

                #region MicroStack.h include
                WS = WS.Replace("//{{{MicroStack_Include}}}", "//{{{MicroStack_Include}}}" + cl + "#include \"UPnPMicroStack.h\"");
                #endregion
                #region MicroStack Veriable Declaration
                WS = WS.Replace("//{{{MICROSTACK_VARIABLE}}}", "//{{{MICROSTACK_VARIABLE}}}" + cl + "void *UPnPmicroStack;");
                #endregion
                #region CreateMicroStack
                if (!Configuration.BareBonesSample)
                {
                    cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                    cs.ident = 1;
                    cs.Append("    // TODO: Each device must have a unique device identifier (UDN)" + cl);
                    cs.Append("	" + this.pc_methodPrefix + "microStack = " + pc_methodPrefix + "CreateMicroStack(MicroStackChain, ");
                    CreateMicroStack_Device_Values(cs, device);
                    cs.Append("\"" + Guid.NewGuid().ToString() + "\", \"0000001\", " + DeviceConf.SSDPCycleTime.ToString() + ", " + DeviceConf.WebPort.ToString() + ");" + cl);
                    WS = WS.Replace("//{{{CREATE_MICROSTACK}}}", "//{{{CREATE_MICROSTACK}}}" + cl + cs.ToString());
                }
                #endregion

                #region InitialEvent Initialization
                if (!Configuration.BareBonesSample)
                {
                    cs = new CodeProcessor(new StringBuilder(), this.Language == LANGUAGES.CPP);
                    BuildStateVariableEventingSample(cs, device, serviceNames);
                    WS = WS.Replace("//{{{STATEVARIABLES_INITIAL_STATE}}}", "//{{{STATEVARIABLES_INITIAL_STATE}}}" + cl + cs.ToString());
                }
                #endregion

                #region IPAddress Monitor
                if (Configuration.DefaultIPAddressMonitor)
                {
                    WS = WS.Replace("//{{{IPAddress_Changed}}}", "//{{{IPAddress_Changed}}}" + cl + "UPnPIPAddressListChanged(UPnPmicroStack);");

                    if (Configuration.TargetPlatform == ServiceGenerator.PLATFORMS.MICROSTACK_WINSOCK2)
                    {
                        WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_WINSOCK2_IPADDRESS_MONITOR}}}", "//{{{END_WINSOCK2_IPADDRESS_MONITOR}}}", WS);
                        WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_POSIX/WINSOCK1_IPADDRESS_MONITOR}}}", "//{{{END_POSIX/WINSOCK1_IPADDRESS_MONITOR}}}", WS);
                    }
                    else
                    {
                        WS = SourceCodeRepository.RemoveTag("//{{{BEGIN_POSIX/WINSOCK1_IPADDRESS_MONITOR}}}", "//{{{END_POSIX/WINSOCK1_IPADDRESS_MONITOR}}}", WS);
                        WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_WINSOCK2_IPADDRESS_MONITOR}}}", "//{{{END_WINSOCK2_IPADDRESS_MONITOR}}}", WS);
                    }
                }
                else
                {
                    WS = WS.Replace("//{{{IPAddress_Changed}}}", "");
                    WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_WINSOCK2_IPADDRESS_MONITOR}}}", "//{{{END_WINSOCK2_IPADDRESS_MONITOR}}}", WS);
                    WS = SourceCodeRepository.RemoveAndClearTag("//{{{BEGIN_POSIX/WINSOCK1_IPADDRESS_MONITOR}}}", "//{{{END_POSIX/WINSOCK1_IPADDRESS_MONITOR}}}", WS);
                }
                #endregion

                #region Prefixes
                WS = WS.Replace("UPnPAbstraction.h", "_upnpabstraction.h_");
                WS = WS.Replace("pUPnP", "_pupnp_");
                WS = WS.Replace("CUPnP_", "_cupnp_");
                WS = WS.Replace("UPnP/", "upnp/");
                WS = WS.Replace("UPnPControlPointStructs.h", "upnpcontrolpointstructs.h");
                WS = WS.Replace("UPnPDevice", "upnpdevice");
                WS = WS.Replace("UPnPService", "upnpservice");
                WS = WS.Replace("SubscribeForUPnPEvents", "subscribeforupnpevents");
                WS = WS.Replace("UnSubscribeUPnPEvents", "unsubscribeupnpevents");

                WS = WS.Replace("UPnPError", "_upnperror_");
                WS = WS.Replace(" UPnP ", " _upnp_ ");
                WS = WS.Replace("UPnP", this.pc_methodPrefix);
                WS = WS.Replace("ILib", this.pc_methodLibPrefix);
                WS = WS.Replace("_upnperror_", "UPnPError");
                WS = WS.Replace("upnp/", "UPnP/");
                WS = WS.Replace(" _upnp_ ", " UPnP ");
                WS = WS.Replace("_pupnp_", "pUPnP");
                WS = WS.Replace("_cupnp_", "CUPnP_");

                WS = WS.Replace("upnpdevice", "UPnPDevice");
                WS = WS.Replace("upnpservice", "UPnPService");
                WS = WS.Replace("upnpcontrolpointstructs.h", "UPnPControlPointStructs.h");
                WS = WS.Replace("subscribeforupnpevents", "SubscribeForUPnPEvents");
                WS = WS.Replace("unsubscribeupnpevents", "UnSubscribeUPnPEvents");
                WS = WS.Replace("_upnpabstraction.h_", "UPnPAbstraction.h");

                #endregion

                SampleApp = WS;
            }
            #endregion

            Log("UPnP Stack Generation Complete.");

            return true;
        }
        public override void Start(UPnPDevice device)
        {
            if(!Enabled) return;

            UPnPDevice dv = device;
            while(dv.ParentDevice!=null)
            {
                dv = dv.ParentDevice;
            }

            state = UPnPTestStates.Running;
            UPnPService[] _S = device.GetServices("urn:");

            foreach(UPnPService s in _S)
            {
                bool ok = false;
                foreach(UPnPStateVariable v in s.GetStateVariables())
                {
                    if(v.SendEvent)
                    {
                        ok = true;
                        break;
                    }
                }
                if(ok)
                {

                    UPnPDebugObject d = new UPnPDebugObject(s);
                    Uri EventUri = new Uri((string)d.GetField("__eventurl"));

                    IPEndPoint dest = new IPEndPoint(IPAddress.Parse(EventUri.Host),EventUri.Port);
                    HTTPMessage R = new HTTPMessage();
                    R.Directive = "SUBSCRIBE";
                    R.DirectiveObj = HTTPMessage.UnEscapeString(EventUri.PathAndQuery);
                    R.AddTag("Host",dest.ToString());
                    R.AddTag("Callback","<http://" + dv.InterfaceToHost.ToString()+ ":" + NetworkInfo.GetFreePort(10000,50000,dv.InterfaceToHost).ToString() + ">");
                    //R.AddTag("Callback","<http://127.0.0.1:55555>");
                    R.AddTag("NT","upnp:event");
                    R.AddTag("Timeout","Second-15");

                    System.Console.WriteLine(R.GetTag("Callback"));

                    MRE.Reset();
                    SID = "";
                    StartCountDown(30);
                    HTTPRequest rq = new HTTPRequest();
                    rq.OnResponse += new HTTPRequest.RequestHandler(SubscribeSink);

                    AddHTTPMessage(R);

                    rq.PipelineRequest(dest,R,s);
                    MRE.WaitOne(30000,false);
                    AbortCountDown();

                    if (SID=="")
                    {
                        AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE: " + s.ServiceURN + " << FAILED >>");
                        AddEvent(LogImportance.Remark,"Subscribe","Aborting tests");

                        result = "Subscription test failed."; // TODO
                        state = UPnPTestStates.Failed;
                        return;
                    }
                    else
                    {
                        AddEvent(LogImportance.Remark,"Subscribe","SUBSCRIBE: " + s.ServiceURN + " << OK >>");

                        // Renew Test
                        R = new HTTPMessage();
                        R.Directive = "SUBSCRIBE";
                        R.DirectiveObj = HTTPMessage.UnEscapeString(EventUri.PathAndQuery);
                        R.AddTag("Host",dest.ToString());
                        R.AddTag("SID",SID);
                        R.AddTag("Timeout","Second-15");
                        StartCountDown(30);
                        SID = "";
                        MRE.Reset();

                        AddHTTPMessage(R);

                        rq = new HTTPRequest();
                        rq.OnResponse += new HTTPRequest.RequestHandler(SubscribeSink);
                        rq.PipelineRequest(dest,R,s);

                        MRE.WaitOne(30000,false);
                        AbortCountDown();

                        if (SID=="")
                        {
                            AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE (Renew): " + s.ServiceURN + " << FAILED >>");
                            AddEvent(LogImportance.Remark,"Subscribe","Aborting tests");

                            result = "Subscription test failed."; // TODO
                            state = UPnPTestStates.Failed;
                            return;
                        }
                        else
                        {
                            AddEvent(LogImportance.Remark,"Subscribe","SUBSCRIBE (Renew): " + s.ServiceURN + " << OK >>");

                            // Cancel
                            R = new HTTPMessage();
                            R.Directive = "UNSUBSCRIBE";
                            R.DirectiveObj = HTTPMessage.UnEscapeString(EventUri.PathAndQuery);
                            R.AddTag("Host",dest.ToString());
                            R.AddTag("SID",SID);

                            StartCountDown(30);
                            SID = "";
                            MRE.Reset();
                            rq = new HTTPRequest();
                            rq.OnResponse += new HTTPRequest.RequestHandler(CancelSink);

                            AddHTTPMessage(R);

                            rq.PipelineRequest(dest,R,s);

                            MRE.WaitOne(30000,false);
                            AbortCountDown();

                            if (SID=="")
                            {
                                AddEvent(LogImportance.Critical,"Subscribe","UNSUBSCRIBE: " + s.ServiceURN + " << FAILED >>");
                                AddEvent(LogImportance.Remark,"Subscribe","Aborting tests");

                                result = "Subscription test failed.";
                                state = UPnPTestStates.Failed;
                                return;
                            }
                            else
                            {
                                AddEvent(LogImportance.Remark,"Subscribe","UNSUBSCRIBE: " + s.ServiceURN + " << OK >>");
                            }

                            /* Test for duplicate SID
                             * as well as initial events */

                            EventTable.Clear();
                            NumEvents = 0;
                            foreach(UPnPStateVariable V in s.GetStateVariables())
                            {
                                if(V.SendEvent)
                                {
                                    ++ NumEvents;
                                    EventTable[V.Name] = false;
                                    V.OnModified -= new UPnPStateVariable.ModifiedHandler(StateVarModifiedSink);
                                    V.OnModified += new UPnPStateVariable.ModifiedHandler(StateVarModifiedSink);
                                }
                            }
                            if(EventTable.Count>0)
                            {
                                MRE.Reset();
                                s.OnSubscribe -= new UPnPService.UPnPEventSubscribeHandler(OnSubscribeSink);
                                s.OnSubscribe += new UPnPService.UPnPEventSubscribeHandler(OnSubscribeSink);
                                s.UnSubscribe(null);
                                foreach(UPnPStateVariable V in s.GetStateVariables())
                                {
                                    V.Clear();
                                }
                                s.Subscribe(120,null);
                                MRE.WaitOne(30000,false);
                                if(SID=="")
                                {
                                    // Subscribe Failed
                                    AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE(2): " + s.ServiceURN + " << FAILED >>");
                                    AddEvent(LogImportance.Remark,"Subscribe","Aborting tests");

                                    result = "Subscription test failed.";
                                    state = UPnPTestStates.Failed;
                                    return;
                                }
                                else
                                {
                                    if(SID==null)
                                    {
                                        // Duplicate SID
                                        // Subscribe Failed
                                        AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE(2): " + s.ServiceURN + " << FAILED, duplicate SID >>");
                                        AddEvent(LogImportance.Remark,"Subscribe","Aborting tests");

                                        result = "Subscription test failed.";
                                        state = UPnPTestStates.Failed;
                                        return;
                                    }
                                    else
                                    {
                                        // Check Hashtable
                                        IDictionaryEnumerator de = EventTable.GetEnumerator();
                                        bool OK = true;
                                        while(de.MoveNext())
                                        {
                                            if((bool)de.Value==false)
                                            {
                                                // No Event Received
                                                OK = false;
                                                AddEvent(LogImportance.Critical,"Subscribe","   StateVariable: " + (string)de.Key + " >> Event NOT received");
                                            }
                                            else
                                            {
                                                // OK
                                                AddEvent(LogImportance.Remark,"Subscribe","   StateVariable: " + (string)de.Key + " >> Event OK");
                                            }
                                        }
                                        if(OK==false)
                                        {
                                            AddEvent(LogImportance.Critical,"Subscribe","SUBSCRIBE(2): " + s.ServiceURN + " << FAILED, Did not receive all events >>");
                                            AddEvent(LogImportance.Remark,"Subscribe","Aborting tests");

                                            result = "Subscription test failed.";
                                            state = UPnPTestStates.Failed;
                                            return;
                                        }
                                    }
                                }
                            }
                        }

                    }
                }
            }

            result = "Subscribe Tests OK";
            state = UPnPTestStates.Pass;
        }