public UPnPRelayDevice(UPnPDevice device, CpGateKeeper _CP)
        {
            OpenSource.Utilities.InstanceTracker.Add(this);
            ILCB = new InvokeResponseHandler(InvokeResponseSink);
            CP = _CP;
            ProxyDevice = UPnPDevice.CreateRootDevice(750, double.Parse(device.Version), "");
            ProxyDevice.UniqueDeviceName = Guid.NewGuid().ToString();

            ProxyDevice.HasPresentation = false;
            ProxyDevice.FriendlyName = "*" + device.FriendlyName;
            ProxyDevice.Manufacturer = device.Manufacturer;
            ProxyDevice.ManufacturerURL = device.ManufacturerURL;
            ProxyDevice.ModelName = device.ModelName;
            ProxyDevice.DeviceURN = device.DeviceURN;

            foreach (UPnPService S in device.Services)
            {
                UPnPService S2 = (UPnPService)S.Clone();
                foreach (UPnPAction A in S2.Actions)
                {
                    A.ParentService = S2;
                    A.SpecialCase += new UPnPAction.SpecialInvokeCase(InvokeSink);
                }

                UPnPDebugObject dbg = new UPnPDebugObject(S2);

                dbg.SetField("SCPDURL", "_" + S2.ServiceID + "_scpd.xml");
                dbg.SetProperty("ControlURL", "_" + S2.ServiceID + "_control");
                dbg.SetProperty("EventURL", "_" + S2.ServiceID + "_event");
                ProxyDevice.AddService(S2);
            }

            UDNTable[device.UniqueDeviceName] = ProxyDevice;
            ReverseUDNTable[ProxyDevice.UniqueDeviceName] = device.UniqueDeviceName;
            foreach (UPnPDevice _ed in device.EmbeddedDevices)
            {
                ProcessDevice(_ed);
            }
        }
        private void TypeCheckIntegral(CodeProcessor cs, UPnPArgument args)
        {
            UPnPDebugObject obj = new UPnPDebugObject(args.RelatedStateVar.GetNetType());
            switch (args.RelatedStateVar.GetNetType().FullName)
            {
                case "System.SByte":
                case "System.Int16":
                case "System.Int32":
                    cs.Append("	OK = " + pc_methodLibPrefix + "GetLong(p_" + args.Name + ",p_" + args.Name + "Length, &TempLong);" + cl);
                    break;
                case "System.Byte":
                case "System.UInt16":
                case "System.UInt32":
                    cs.Append("	OK = " + pc_methodLibPrefix + "GetULong(p_" + args.Name + ",p_" + args.Name + "Length, &TempULong);" + cl);
                    break;
            }
            cs.Append("	if (OK!=0)" + cl);
            cs.Append("	{" + cl);
            if (Configuration.ExplicitErrorEncoding == true)
            {
                cs.Append("		" + pc_methodPrefix + "Response_Error(ReaderObject,402,\"Argument[" + args.Name + "] illegal value\");" + cl);
            }
            else
            {
                cs.Append("		" + pc_methodPrefix + "Response_Error(ReaderObject,402,\"Illegal value\");" + cl);
            }
            cs.Append("		return;" + cl);
            cs.Append("	}" + cl);

            bool endtag = false;
            switch (args.RelatedStateVar.GetNetType().FullName)
            {
                case "System.SByte":
                case "System.Int16":
                case "System.Int32":
                    if (args.RelatedStateVar.Minimum == null && args.RelatedStateVar.Maximum == null)
                    {
                        // No need to check anything since this is without bounds.
                    }
                    else
                    {
                        // Check lower and upper bounds.
                        endtag = true;
                        cs.Append("	else" + cl);
                        cs.Append("	{" + cl);
                        if (!Configuration.DynamicObjectModel)
                        {
                            cs.Append("		if (!(TempLong>=");
                            if (args.RelatedStateVar.Minimum != null)
                            {
                                cs.Append("(long)0x" + ToHex(args.RelatedStateVar.Minimum));
                            }
                            else
                            {
                                cs.Append("(long)0x" + ToHex(obj.GetStaticField("MinValue")));
                            }
                            cs.Append(" && TempLong<=");
                            if (args.RelatedStateVar.Maximum != null)
                            {
                                cs.Append("(long)0x" + ToHex(args.RelatedStateVar.Maximum));
                            }
                            else
                            {
                                cs.Append("(long)0x" + ToHex(obj.GetStaticField("MaxValue")));
                            }
                            cs.Append("))" + cl);
                        }
                        else
                        {
                            string vIdent = DeviceObjectGenerator.GetStateVariableIdentifier(args.RelatedStateVar);

                            cs.Append("	OK = 0;" + cs.NewLine);
                            cs.Append("	if (" + vIdent + "->MinMaxStep[0]!=NULL)" + cs.NewLine);
                            cs.Append("	{" + cs.NewLine);
                            cs.Append("		" + pc_methodLibPrefix + "GetLong(" + vIdent + "->MinMaxStep[0],(int)strlen(" + vIdent + "->MinMaxStep[0]), &TempLong2);" + cl);
                            cs.Append("		if (TempLong<TempLong2){OK=1;}" + cs.NewLine);
                            cs.Append("	}" + cs.NewLine);
                            cs.Append("	if (" + vIdent + "->MinMaxStep[1]!=NULL)" + cs.NewLine);
                            cs.Append("	{" + cs.NewLine);
                            cs.Append("		" + pc_methodLibPrefix + "GetLong(" + vIdent + "->MinMaxStep[1],(int)strlen(" + vIdent + "->MinMaxStep[1]), &TempLong2);" + cl);
                            cs.Append("		if (TempLong>TempLong2){OK=1;}" + cs.NewLine);
                            cs.Append("	}" + cs.NewLine);
                            cs.Append("	if (OK!=0)" + cs.NewLine);
                        }
                        cs.Append("		{" + cl);
                        if (Configuration.ExplicitErrorEncoding == true)
                        {
                            cs.Append("		  " + pc_methodPrefix + "Response_Error(ReaderObject,402,\"Argument[" + args.Name + "] out of Range\");" + cl);
                        }
                        else
                        {
                            cs.Append("		  " + pc_methodPrefix + "Response_Error(ReaderObject,402,\"Illegal value\");" + cl);
                        }
                        cs.Append("		  return;" + cl);
                        cs.Append("		}" + cl);
                    }
                    break;
                case "System.Byte":
                case "System.UInt16":
                case "System.UInt32":
                    if (args.RelatedStateVar.Minimum == null && args.RelatedStateVar.Maximum == null)
                    {
                        // No need to check anything since this is an int without bounds.
                    }
                    else
                    {
                        endtag = true;
                        cs.Append("	else" + cl);
                        cs.Append("	{" + cl);
                        if (!this.Configuration.DynamicObjectModel)
                        {
                            cs.Append("		if (!(TempULong>=");
                            if (args.RelatedStateVar.Minimum != null)
                            {
                                cs.Append("(unsigned long)0x" + ToHex(args.RelatedStateVar.Minimum));
                            }
                            else
                            {
                                cs.Append("(unsigned long)0x" + ToHex(obj.GetStaticField("MinValue")));
                            }
                            cs.Append(" && TempULong<=");
                            if (args.RelatedStateVar.Maximum != null)
                            {
                                cs.Append("(unsigned long)0x" + ToHex(args.RelatedStateVar.Maximum));
                            }
                            else
                            {
                                cs.Append("(unsigned long)0x" + ToHex(obj.GetStaticField("MaxValue")));
                            }
                            cs.Append("))" + cl);
                        }
                        else
                        {
                            string vIdent = DeviceObjectGenerator.GetStateVariableIdentifier(args.RelatedStateVar);

                            cs.Append("	OK = 0;" + cs.NewLine);
                            cs.Append("	if (" + vIdent + "->MinMaxStep[0]!=NULL)" + cs.NewLine);
                            cs.Append("	{" + cs.NewLine);
                            cs.Append("		" + pc_methodLibPrefix + "GetULong(" + vIdent + "->MinMaxStep[0],(int)strlen(" + vIdent + "->MinMaxStep[0]), &TempULong2);" + cl);
                            cs.Append("		if (TempULong<TempULong2){OK=1;}" + cs.NewLine);
                            cs.Append("	}" + cs.NewLine);
                            cs.Append("	if (" + vIdent + "->MinMaxStep[1]!=NULL)" + cs.NewLine);
                            cs.Append("	{" + cs.NewLine);
                            cs.Append("		" + pc_methodLibPrefix + "GetULong(" + vIdent + "->MinMaxStep[1],(int)strlen(" + vIdent + "->MinMaxStep[1]), &TempULong2);" + cl);
                            cs.Append("		if (TempULong>TempULong2){OK=1;}" + cs.NewLine);
                            cs.Append("	}" + cs.NewLine);
                            cs.Append("	if (OK!=0)" + cs.NewLine);
                        }
                        cs.Append("		{" + cl);
                        if (Configuration.ExplicitErrorEncoding == true)
                        {
                            cs.Append("		  " + pc_methodPrefix + "Response_Error(ReaderObject,402,\"Argument[" + args.Name + "] out of Range\");" + cl);
                        }
                        else
                        {
                            cs.Append("		  " + pc_methodPrefix + "Response_Error(ReaderObject,402,\"Illegal value\");" + cl);
                        }
                        cs.Append("		  return;" + cl);
                        cs.Append("		}" + cl);
                    }
                    break;
            }

            switch (args.RelatedStateVar.GetNetType().FullName)
            {
                case "System.SByte":
                case "System.Int16":
                case "System.Int32":
                    cs.Append("	_" + args.Name + " = (" + ToCType(args.RelatedStateVar.GetNetType().FullName) + ")TempLong;" + cl);
                    break;
                case "System.Byte":
                case "System.UInt16":
                case "System.UInt32":
                    cs.Append("	_" + args.Name + " = (" + ToCType(args.RelatedStateVar.GetNetType().FullName) + ")TempULong;" + cl);
                    break;
            }
            if (endtag == true) cs.Append(" }" + cl);
        }
        private void Fix(UPnPDevice device, int number, Hashtable serviceNameTable)
        {
            device.User3 = new object[9]{
                                            device.SerialNumber,
                                            device.FriendlyName,
                                            device.Manufacturer,
                                            device.ManufacturerURL,
                                            device.ModelDescription,
                                            device.ModelName,
                                            device.ModelNumber,
                                            device.ModelURL,
                                            device.ProductCode};
            if (device.FriendlyName != "%s")
            {
                FriendlyNameTable[device] = device.FriendlyName;
            }
            if (device.Root)
            {
                device.UniqueDeviceName = "%s";
            }
            else
            {
                device.UniqueDeviceName = "%s_" + number.ToString();
            }
            device.SerialNumber = "%s";
            device.FriendlyName = "%s";
            if (Configuration.DynamicObjectModel)
            {
                device.Manufacturer = "%s";
                device.ManufacturerURL = "%s";
                device.ModelDescription = "%s";
                device.ModelName = "%s";
                device.ModelNumber = "%s";
                device.ModelURL = new Uri("http://255.255.255.255:255/");
                device.ProductCode = "%s";
            }
            foreach (UPnPService service in device.Services)
            {
                UPnPDebugObject obj = new UPnPDebugObject(service);
                obj.SetField("SCPDURL", (string)serviceNameTable[service] + "/scpd.xml");
                obj.SetField("__controlurl", (string)serviceNameTable[service] + "/control");
                bool eventOK = false;
                foreach (UPnPStateVariable sv in service.GetStateVariables())
                {
                    if (sv.SendEvent)
                    {
                        eventOK = true;
                        break;
                    }
                }
                if (eventOK)
                {
                    obj.SetField("__eventurl", (string)serviceNameTable[service] + "/event");
                }
                else
                {
                    obj.SetField("__eventurl", "");
                }
            }

            foreach (UPnPDevice d in device.EmbeddedDevices)
            {
                Fix(d, ++number, serviceNameTable);
            }
        }
        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);
            }
        }
        protected static void GenerateActionLookupTable_Service(UPnPService s, Hashtable t)
        {
            Hashtable lookupTable = new Hashtable();
            t[s] = lookupTable;

            int i=0;

            foreach(UPnPAction a in s.Actions)
            {
                StringBuilder sb = new StringBuilder();
                StringWriter SW = new StringWriter(sb);
                XmlTextWriter X = new XmlTextWriter(SW);

                UPnPDebugObject dobj = new UPnPDebugObject(a);
                dobj.InvokeNonStaticMethod("GetXML",new object[1]{X});

                lookupTable[a] = new object[2]{i,sb.Length};
                i+=sb.Length;
            }
        }
        private void TypeCheckIntegral(CodeProcessor cs, UPnPArgument args)
        {
            UPnPDebugObject obj = new UPnPDebugObject(args.RelatedStateVar.GetNetType());
            switch(args.RelatedStateVar.GetNetType().FullName)
            {
                case "System.SByte":
                case "System.Int16":
                case "System.Int32":
                    cs.Append("	OK = "+pc_methodLibPrefix+"GetLong(p_" + args.Name + ",p_" + args.Name + "Length, &TempLong);"+cl);
                    break;
                case "System.Byte":
                case "System.UInt16":
                case "System.UInt32":
                    cs.Append("	OK = "+pc_methodLibPrefix+"GetULong(p_" + args.Name + ",p_" + args.Name + "Length, &TempULong);"+cl);
                    break;
            }
            cs.Append("	if (OK != 0)"+cl);
            cs.Append("	{"+cl);
            cs.Append("		"+pc_methodPrefix+"Response_Error(ReaderObject, 402, \"Argument[" + args.Name + "] illegal value\");"+cl);
            cs.Append("		return;"+cl);
            cs.Append("	}"+cl);

            bool endtag = false;
            switch(args.RelatedStateVar.GetNetType().FullName)
            {
                case "System.SByte":
                case "System.Int16":
                case "System.Int32":
                    if ((args.RelatedStateVar.GetNetType().FullName == "System.Int32") && (args.RelatedStateVar.Minimum==null && args.RelatedStateVar.Maximum==null))
                    {
                        // No need to check anything since this is an int without bounds.
                    }
                    else
                    {
                        // Check lower and upper bounds.
                        endtag = true;
                        cs.Append("	else"+cl);
                        cs.Append("	{"+cl);
                        cs.Append("		if (!(TempLong >= ");
                        if (args.RelatedStateVar.Minimum!=null)
                        {
                            cs.Append("(long)0x" + ToHex(args.RelatedStateVar.Minimum));
                        }
                        else
                        {
                            cs.Append("(long)0x" + ToHex(obj.GetStaticField("MinValue")));
                        }
                        cs.Append(" && TempLong <= ");
                        if (args.RelatedStateVar.Maximum!=null)
                        {
                            cs.Append("(long)0x"+ToHex(args.RelatedStateVar.Maximum));
                        }
                        else
                        {
                            cs.Append("(long)0x"+ToHex(obj.GetStaticField("MaxValue")));
                        }
                        cs.Append("))"+cl);
                        cs.Append("		{"+cl);
                        cs.Append("		  "+pc_methodPrefix+"Response_Error(ReaderObject, 402, \"Argument[" + args.Name + "] out of Range\");"+cl);
                        cs.Append("		  return;"+cl);
                        cs.Append("		}"+cl);
                    }
                    break;
                case "System.Byte":
                case "System.UInt16":
                case "System.UInt32":
                    if ((args.RelatedStateVar.GetNetType().FullName == "System.UInt32") && (args.RelatedStateVar.Minimum==null && args.RelatedStateVar.Maximum==null))
                    {
                        // No need to check anything since this is an int without bounds.
                    }
                    else
                    {
                        endtag = true;
                        cs.Append("	else"+cl);
                        cs.Append("	{"+cl);
                        cs.Append("		if (!(TempULong >= ");
                        if (args.RelatedStateVar.Minimum!=null)
                        {
                            cs.Append("(unsigned long)0x"+ToHex(args.RelatedStateVar.Minimum));
                        }
                        else
                        {
                            cs.Append("(unsigned long)0x"+ToHex(obj.GetStaticField("MinValue")));
                        }
                        cs.Append(" && TempULong<=");
                        if (args.RelatedStateVar.Maximum!=null)
                        {
                            cs.Append("(unsigned long)0x"+ToHex(args.RelatedStateVar.Maximum));
                        }
                        else
                        {
                            cs.Append("(unsigned long)0x"+ToHex(obj.GetStaticField("MaxValue")));
                        }
                        cs.Append("))"+cl);
                        cs.Append("		{"+cl);
                        cs.Append("		  "+pc_methodPrefix+"Response_Error(ReaderObject, 402, \"Argument[" + args.Name + "] out of Range\");"+cl);
                        cs.Append("		  return;"+cl);
                        cs.Append("		}"+cl);
                    }
                    break;
            }

            switch(args.RelatedStateVar.GetNetType().FullName)
            {
                case "System.SByte":
                case "System.Int16":
                case "System.Int32":
                    cs.Append("	_" + args.Name + " = (" + ToCType(args.RelatedStateVar.GetNetType().FullName) + ")TempLong;"+cl);
                    break;
                case "System.Byte":
                case "System.UInt16":
                case "System.UInt32":
                    cs.Append("	_" + args.Name + " = (" + ToCType(args.RelatedStateVar.GetNetType().FullName) + ")TempULong;"+cl);
                    break;
            }
            if (endtag == true) cs.Append(" }"+cl);
        }
        protected static void BuildActionStructs(CodeProcessor cs, UPnPDevice d)
        {
            foreach(UPnPDevice ed in d.EmbeddedDevices)
            {
                BuildActionStructs(cs,ed);
            }
            foreach(UPnPService s in d.Services)
            {
                string stringX;
                int stringXLen;
                StringBuilder sb = new StringBuilder();
                StringWriter SW = new StringWriter(sb);
                XmlTextWriter X = new XmlTextWriter(SW);

                foreach(UPnPAction a in s.Actions)
                {
                    UPnPDebugObject dobj = new UPnPDebugObject(a);
                    dobj.InvokeNonStaticMethod("GetXML",new object[1]{X});
                }
                InjectCompressedString(out stringX,out stringXLen,sb.ToString(),cs.NewLine);

                cs.Append("struct UPnP_ActionTable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+cs.NewLine);
                cs.Append("{"+cs.NewLine);
                cs.Append("	char Reserved["+stringXLen.ToString()+"];"+cs.NewLine);
                cs.Append("	int ReservedXL;"+cs.NewLine);
                cs.Append("	int ReservedUXL;"+cs.NewLine);
                cs.Append("};"+cs.NewLine);

                foreach(UPnPAction a in s.Actions)
                {
                    cs.Append("struct UPnP_Action_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_"+a.Name+cs.NewLine);
                    cs.Append("{"+cs.NewLine);
                    cs.Append("	int Reserved;"+cs.NewLine);
                    cs.Append("	int Reserved2;"+cs.NewLine);
                    cs.Append("};"+cs.NewLine);
                }
            }
        }
 private void serviceTypeTextBox_TextChanged(object sender, System.EventArgs e)
 {
     if (selectedItem.GetType() != typeof(UPnPService)) return;
     UPnPDebugObject dobj = new UPnPDebugObject(selectedItem);
     dobj.SetProperty("ServiceURN", serviceTypeTextBox.Text);
     serviceTypeTextBox.Text = ((UPnPService)selectedItem).ServiceURN;
 }
        private void Fix(UPnPDevice device, int number, Hashtable serviceNameTable)
        {
            if (device.Root)
            {
                device.UniqueDeviceName = "%s";
            }
            else
            {
                device.UniqueDeviceName = "%s_" + number.ToString();
            }
            device.SerialNumber = "%s";
            foreach(UPnPService service in device.Services)
            {
                UPnPDebugObject obj = new UPnPDebugObject(service);
                obj.SetField("SCPDURL",(string)serviceNameTable[service] + "/scpd.xml");
                obj.SetField("__controlurl",(string)serviceNameTable[service] + "/control");
                obj.SetField("__eventurl",(string)serviceNameTable[service] + "/event");
            }

            foreach(UPnPDevice d in device.EmbeddedDevices)
            {
                Fix(d, ++number, serviceNameTable);
            }
        }
        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;
        }
        /// <summary>
        /// Generates a UPnPService object from an SCPD XML
        /// </summary>
        /// <param name="SCPD_XML">XML String</param>
        /// <returns>UPnPService</returns>
        public static UPnPService GenerateServiceFromSCPD(string SCPD_XML)
        {
            if (SCPD_XML == null) return null;
            UPnPService s = new UPnPService(1, null);
            UPnPDebugObject obj = new UPnPDebugObject(s);
            obj.InvokeNonStaticMethod("ParseSCPD", new Object[1] { SCPD_XML });

            return (s);
        }
        /// <summary>
        /// Generates Device side implementation from SCPD XML
        /// </summary>
        /// <param name="ClassName">Class Name to build</param>
        /// <param name="ns">Namespace to use</param>
        /// <param name="SavePath">Path to save source</param>
        /// <param name="ServiceID">Service ID to use</param>
        /// <param name="ServiceURN">Service URN to use</param>
        /// <param name="SCPD_XML">SCPD XML String</param>
        public static void Generate(String ClassName, String ns, String SavePath, String ServiceID, String ServiceURN, String SCPD_XML)
        {
            UPnPService s = ServiceGenerator.GenerateServiceFromSCPD(SCPD_XML);
            UPnPDebugObject dobj = new UPnPDebugObject(s);

            int ServiceURversion = 1;
            string[] xx = ServiceURN.Split(':');
            if (xx.Length > 2) int.TryParse(xx[xx.Length - 1], out ServiceURversion);

            DText p = new DText();
            p.ATTRMARK = ":";
            p[0] = ServiceURN;

            string v = p[p.DCOUNT()];
            dobj.InvokeNonStaticMethod("SetVersion", new Object[1] { v });
            String cl = "\r\n";

            StringBuilder cs = new StringBuilder();
            UPnPArgument[] Args;
            UPnPArgument arg;
            UPnPStateVariable[] SV = s.GetStateVariables();

            cs.Append("using OpenSource.UPnP;" + cl + cl);
            cs.Append("namespace " + ns + cl);
            cs.Append("{\r\n");
            cs.Append("    /// <summary>" + cl);
            cs.Append("    /// Transparent DeviceSide UPnP Service" + cl);
            cs.Append("    /// </summary>" + cl);
            cs.Append("    public class " + ClassName + " : IUPnPService" + cl);
            cs.Append("    {" + cl + cl);
            cs.Append("        // Place your declarations above this line\r\n");
            cs.Append("\r\n");
            cs.Append("        #region AutoGenerated Code Section [Do NOT Modify, unless you know what you're doing]\r\n");
            cs.Append("        //{{{{{ Begin Code Block\r\n");
            cs.Append("\r\n");
            cs.Append("        private _" + ClassName + " _S;\r\n");
            cs.Append("        public static string URN = \"" + ServiceURN + "\";\r\n");
            cs.Append("        public double VERSION\r\n");
            cs.Append("        {\r\n");
            cs.Append("           get\r\n");
            cs.Append("           {\r\n");
            cs.Append("               return(double.Parse(_S.GetUPnPService().Version));\r\n");
            cs.Append("           }\r\n");
            cs.Append("        }\r\n\r\n");

            // Build Enumerations
            Hashtable elist = BuildEnumerations(SV);
            IDictionaryEnumerator el = elist.GetEnumerator();
            VarData vd;
            while (el.MoveNext())
            {
                vd = (VarData)el.Value;
                cs.Append("        public enum Enum_" + vd.VariableName + "\r\n");
                cs.Append("        {\r\n");
                foreach (EnumStruct vs in vd.Enumerations)
                {
                    cs.Append("            " + vs.EnumName + ",\r\n");
                }
                cs.Append("        }\r\n");

                cs.Append("        public Enum_" + vd.VariableName + " ");
                if (s.GetStateVariableObject(vd.VariableName).SendEvent == true)
                {
                    cs.Append("Evented_");
                }
                cs.Append(vd.VariableName + "\r\n");
                cs.Append("        {\r\n");
                cs.Append("            set\r\n");
                cs.Append("            {\r\n");
                cs.Append("               string v = \"\";\r\n");
                cs.Append("               switch(value)\r\n");
                cs.Append("               {\r\n");
                foreach (EnumStruct vs in vd.Enumerations)
                {
                    cs.Append("                  case Enum_" + vd.VariableName + "." + vs.EnumName + ":\r\n");
                    cs.Append("                     v = \"" + vs.EnumValue + "\";\r\n");
                    cs.Append("                     break;\r\n");
                }
                cs.Append("               }\r\n");
                cs.Append("               _S.SetStateVariable(\"" + vd.VariableName + "\",v);\r\n");
                cs.Append("            }\r\n");
                cs.Append("            get\r\n");
                cs.Append("            {\r\n");
                cs.Append("               Enum_" + vd.VariableName + " RetVal = 0;\r\n");
                cs.Append("               string v = (string)_S.GetStateVariable(\"" + vd.VariableName + "\");\r\n");
                cs.Append("               switch(v)\r\n");
                cs.Append("               {\r\n");
                foreach (EnumStruct vs in vd.Enumerations)
                {
                    cs.Append("                  case \"" + vs.EnumValue + "\":\r\n");
                    cs.Append("                     RetVal = Enum_" + vd.VariableName + "." + vs.EnumName + ";\r\n");
                    cs.Append("                     break;\r\n");
                }
                cs.Append("               }\r\n");
                cs.Append("               return(RetVal);\r\n");
                cs.Append("           }\r\n");
                cs.Append("        }\r\n");
            }

            el.Reset();
            while (el.MoveNext())
            {
                vd = (VarData)el.Value;
                cs.Append("        static public string Enum_" + vd.VariableName + "_ToString(Enum_" + vd.VariableName + " en)\r\n");
                cs.Append("        {\r\n");
                cs.Append("            string RetVal = \"\";\r\n");
                cs.Append("            switch(en)\r\n");
                cs.Append("            {\r\n");
                foreach (EnumStruct vs in vd.Enumerations)
                {
                    cs.Append("                case Enum_" + vd.VariableName + "." + vs.EnumName + ":\r\n");
                    cs.Append("                    RetVal = \"" + vs.EnumValue + "\";\r\n");
                    cs.Append("                    break;\r\n");
                }
                cs.Append("            }\r\n");
                cs.Append("            return(RetVal);\r\n");
                cs.Append("        }\r\n");

                // Build Easy Way to get All Values
                cs.Append("        static public string[] Values_" + vd.VariableName + "\r\n");
                cs.Append("        {\r\n");
                cs.Append("            get\r\n");
                cs.Append("            {\r\n");
                cs.Append("                string[] RetVal = new string[" + vd.Enumerations.Count.ToString() + "]{");
                string EasyStrings = "";
                foreach (EnumStruct vs in vd.Enumerations)
                {
                    if (EasyStrings == "")
                    {
                        EasyStrings = "\"" + vs.EnumValue + "\"";
                    }
                    else
                    {
                        EasyStrings = "\"" + vs.EnumValue + "\"," + EasyStrings;
                    }
                }
                cs.Append(EasyStrings + "};\r\n");
                cs.Append("                return(RetVal);\r\n");
                cs.Append("            }\r\n");
                cs.Append("        }\r\n");
            }

            cs.Append("        public delegate void OnStateVariableModifiedHandler(" + ClassName + " sender);\r\n");
            foreach (UPnPStateVariable V in SV)
            {
                cs.Append("        public event OnStateVariableModifiedHandler OnStateVariableModified_" + V.Name + ";\r\n");
            }

            foreach (UPnPStateVariable V in SV)
            {
                if (elist.ContainsKey(V.Name) == false)
                {
                    // Build Accessors
                    cs.Append("        public " + V.GetNetType().FullName + " ");
                    if (V.SendEvent == true)
                    {
                        cs.Append("Evented_");
                    }
                    cs.Append(V.Name + "\r\n");
                    cs.Append("        {\r\n");
                    cs.Append("            get\r\n");
                    cs.Append("            {\r\n");
                    cs.Append("               return((" + V.GetNetType().FullName + ")_S.GetStateVariable(\"" + V.Name + "\"));\r\n");
                    cs.Append("            }\r\n");
                    cs.Append("            set\r\n");
                    cs.Append("            {\r\n");
                    cs.Append("               _S.SetStateVariable(\"" + V.Name + "\", value);\r\n");
                    cs.Append("            }\r\n");
                    cs.Append("        }\r\n");
                }
            }
            foreach (UPnPStateVariable V in SV)
            {
                cs.Append("        public UPnPModeratedStateVariable.IAccumulator Accumulator_");
                cs.Append(V.Name + "\r\n");
                cs.Append("        {\r\n");
                cs.Append("            get\r\n");
                cs.Append("            {\r\n");
                cs.Append("                 return(((UPnPModeratedStateVariable)_S.GetUPnPService().GetStateVariableObject(\"" + V.Name + "\")).Accumulator);\r\n");
                cs.Append("            }\r\n");
                cs.Append("            set\r\n");
                cs.Append("            {\r\n");
                cs.Append("                 ((UPnPModeratedStateVariable)_S.GetUPnPService().GetStateVariableObject(\"" + V.Name + "\")).Accumulator = value;\r\n");
                cs.Append("            }\r\n");
                cs.Append("        }\r\n");
                cs.Append("        public double ModerationDuration_" + V.Name + "\r\n");
                cs.Append("        {\r\n");
                cs.Append("            get\r\n");
                cs.Append("            {\r\n");
                cs.Append("                 return(((UPnPModeratedStateVariable)_S.GetUPnPService().GetStateVariableObject(\"" + V.Name + "\")).ModerationPeriod);\r\n");
                cs.Append("            }\r\n");
                cs.Append("            set\r\n");
                cs.Append("            {\r\n");
                cs.Append("                 ((UPnPModeratedStateVariable)_S.GetUPnPService().GetStateVariableObject(\"" + V.Name + "\")).ModerationPeriod = value;\r\n");
                cs.Append("            }\r\n");
                cs.Append("        }\r\n");
            }

            // Build MethodDelegates
            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("        public delegate ");
                if (A.HasReturnValue == false)
                {
                    cs.Append("void ");
                }
                else
                {
                    cs.Append(A.GetRetArg().RelatedStateVar.GetNetType().FullName + " ");
                }
                cs.Append("Delegate_" + A.Name + "(");
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if (arg.IsReturnValue == false)
                    {
                        if (arg.Direction == "out")
                        {
                            cs.Append("out ");
                        }
                        if (arg.RelatedStateVar.AllowedStringValues == null)
                        {
                            cs.Append(arg.RelatedStateVar.GetNetType().FullName + " ");
                        }
                        else
                        {
                            cs.Append(ClassName + ".Enum_" + arg.RelatedStateVar.Name + " ");
                        }
                        cs.Append(arg.Name);
                        if (i < Args.Length - 1)
                        {
                            cs.Append(", ");
                        }
                    }
                }
                cs.Append(");\r\n");
            }

            // Build Overriding Delegates
            cs.Append("\r\n");
            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("        public Delegate_" + A.Name + " External_" + A.Name + " = null;\r\n");
            }
            cs.Append("\r\n");

            // Build Ability to remove Optional State Variables
            foreach (UPnPStateVariable V in s.GetStateVariables())
            {
                cs.Append("        public void RemoveStateVariable_" + V.Name + "()\r\n");
                cs.Append("        {\r\n");
                cs.Append("            _S.GetUPnPService().RemoveStateVariable(_S.GetUPnPService().GetStateVariableObject(\"" + V.Name + "\"));\r\n");
                cs.Append("        }\r\n");
            }

            // Build Ability to remove Optional Actions
            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("        public void RemoveAction_" + A.Name + "()\r\n");
                cs.Append("        {\r\n");
                cs.Append("             _S.GetUPnPService().RemoveMethod(\"" + A.Name + "\");\r\n");
                cs.Append("        }\r\n");
            }
            // Add Helper Methods
            cs.Append("        public System.Net.IPEndPoint GetCaller()\r\n");
            cs.Append("        {\r\n");
            cs.Append("             return(_S.GetUPnPService().GetCaller());\r\n");
            cs.Append("        }\r\n");
            cs.Append("        public System.Net.IPEndPoint GetReceiver()\r\n");
            cs.Append("        {\r\n");
            cs.Append("             return(_S.GetUPnPService().GetReceiver());\r\n");
            cs.Append("        }\r\n");
            cs.Append("\r\n");

            // Build Private Class
            cs.Append("        private class _" + ClassName + "\r\n");
            cs.Append("        {\r\n");
            cs.Append("            private " + ClassName + " Outer = null;\r\n");
            cs.Append("            private UPnPService S;\r\n");
            cs.Append("            internal _" + ClassName + "(" + ClassName + " n)\r\n");
            cs.Append("            {\r\n");
            cs.Append("                Outer = n;\r\n");
            cs.Append("                S = BuildUPnPService();\r\n");
            cs.Append("            }\r\n");
            cs.Append("            public UPnPService GetUPnPService()\r\n");
            cs.Append("            {\r\n");
            cs.Append("                return(S);\r\n");
            cs.Append("            }\r\n");
            cs.Append("            public void SetStateVariable(string VarName, object VarValue)\r\n");
            cs.Append("            {\r\n");
            cs.Append("               S.SetStateVariable(VarName,VarValue);\r\n");
            cs.Append("            }\r\n");
            cs.Append("            public object GetStateVariable(string VarName)\r\n");
            cs.Append("            {\r\n");
            cs.Append("               return(S.GetStateVariable(VarName));\r\n");
            cs.Append("            }\r\n");
            cs.Append("            protected UPnPService BuildUPnPService()\r\n");
            cs.Append("            {\r\n");
            cs.Append("                UPnPStateVariable[] RetVal = new UPnPStateVariable[" + SV.Length.ToString() + "];\r\n");
            for (int i = 0; i < SV.Length; ++i)
            {
                cs.Append("                RetVal[" + i.ToString() + "] = new UPnPModeratedStateVariable(\"" + SV[i].Name + "\", typeof(" + SV[i].GetNetType().FullName + "), " + SV[i].SendEvent.ToString().ToLower() + ");\r\n");

                if ((SV[i].Maximum != null) ||
                    (SV[i].Minimum != null) ||
                    (SV[i].Step != null))
                {
                    cs.Append("                RetVal[" + i.ToString() + "].SetRange(");
                    if (SV[i].Minimum == null)
                    {
                        cs.Append("null");
                    }
                    else
                    {
                        cs.Append("(" + SV[i].Minimum.GetType().FullName + ")(" + SV[i].Minimum.ToString() + ")");
                    }
                    cs.Append(",");

                    if (SV[i].Maximum == null)
                    {
                        cs.Append("null");
                    }
                    else
                    {
                        cs.Append("(" + SV[i].Maximum.GetType().FullName + ")(" + SV[i].Maximum.ToString() + ")");
                    }
                    cs.Append(",");

                    if (SV[i].Step == null)
                    {
                        cs.Append("null");
                    }
                    else
                    {
                        cs.Append("(" + SV[i].Step.GetType().FullName + ")" + SV[i].Step.ToString());
                    }
                    cs.Append(");\r\n");
                }

                if (SV[i].DefaultValue != null)
                {
                    cs.Append("                RetVal[" + i.ToString() + "].DefaultValue = UPnPService.CreateObjectInstance(typeof(" + SV[i].GetNetType().FullName + "),\"" + UPnPService.SerializeObjectInstance(SV[i].DefaultValue) + "\");\r\n");
                    //cs.Append("                RetVal[" + i.ToString() + "].DefaultValue = (" + SV[i].GetNetType().FullName + ")(\"" + UPnPService.SerializeObjectInstance(SV[i].DefaultValue) + "\";\r\n");
                }
                if (SV[i].AllowedStringValues != null)
                {
                    cs.Append("                RetVal[" + i.ToString() + "].AllowedStringValues = new string[" +
                        SV[i].AllowedStringValues.Length.ToString() + "]{");
                    for (int ai = 0; ai < SV[i].AllowedStringValues.Length; ++ai)
                    {
                        cs.Append("\"" + SV[i].AllowedStringValues[ai] + "\"");
                        if (ai < SV[i].AllowedStringValues.Length - 1)
                        {
                            cs.Append(", ");
                        }
                    }
                    cs.Append("};\r\n");
                }

                System.Collections.IList e = s.Actions;
                foreach (UPnPAction A in e)
                {
                    foreach (UPnPArgument ag in A.ArgumentList)
                    {
                        if (ag.RelatedStateVar.Name == SV[i].Name)
                        {
                            cs.Append("                RetVal[" + i.ToString() + "].AddAssociation(\"" + A.Name + "\", \"" + ag.Name + "\");\r\n");
                        }
                    }
                }
            }
            // Build UPnPService
            cs.Append("\r\n");
            cs.Append("                UPnPService S = new UPnPService(" +
                ServiceURversion.ToString() + ", \"" + ServiceID + "\", URN, true, this);\r\n");           // WAS: s.Version + ", \"" + ServiceID + "\", \"" + ServiceURN + "\", true, this);\r\n");
            cs.Append("                for(int i=0;i<RetVal.Length;++i)\r\n");
            cs.Append("                {\r\n");
            cs.Append("                   S.AddStateVariable(RetVal[i]);\r\n");
            cs.Append("                }\r\n");
            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("                S.AddMethod(\"" + A.Name + "\");\r\n");
            }

            cs.Append("                return(S);\r\n");
            cs.Append("            }\r\n\r\n");

            System.Collections.IList ee = s.Actions;
            foreach (UPnPAction A in ee)
            {
                if (A.HasReturnValue)
                {
                    cs.Append("            [OpenSource.UPnP.ReturnArgument(\"" + A.GetRetArg().Name + "\")]" + cl);
                }
                cs.Append("            public ");
                if (A.HasReturnValue == false)
                {
                    cs.Append("void ");
                }
                else
                {
                    cs.Append(A.GetRetArg().RelatedStateVar.GetNetType().FullName + " ");
                }

                cs.Append(A.Name + "(");
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if (arg.IsReturnValue == false)
                    {
                        if (arg.Direction == "out")
                        {
                            cs.Append("out ");
                        }
                        cs.Append(arg.RelatedStateVar.GetNetType().FullName + " ");
                        cs.Append(arg.Name);
                        if (i < Args.Length - 1)
                        {
                            cs.Append(", ");
                        }
                    }
                }
                cs.Append(")" + cl);
                cs.Append("            {\r\n");

                // Convert to Enum if neccessary
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if ((arg.IsReturnValue == false) &&
                    (arg.RelatedStateVar.AllowedStringValues != null))
                    {
                        cs.Append("                Enum_" + arg.RelatedStateVar.Name + " e_" + arg.Name + ";\r\n");
                        if (arg.Direction == "in")
                        {
                            cs.Append("                switch(" + arg.Name + ")\r\n");
                            cs.Append("                {\r\n");
                            vd = (VarData)elist[arg.RelatedStateVar.Name];
                            foreach (EnumStruct ss in vd.Enumerations)
                            {
                                cs.Append("                    case \"" + ss.EnumValue + "\":\r\n");
                                cs.Append("                        e_" + arg.Name + " = Enum_" + arg.RelatedStateVar.Name + "." + ss.EnumName + ";\r\n");
                                cs.Append("                        break;\r\n");
                            }
                            cs.Append("                    default:\r\n");
                            cs.Append("                        e_" + arg.Name + " = 0;\r\n");
                            cs.Append("                        break;\r\n");
                            cs.Append("                }\r\n");

                        }
                    }
                }

                // Make Method Call
                if (A.HasReturnValue == true)
                {
                    cs.Append("                object RetObj = null;\r\n");
                }
                cs.Append("                if (Outer.External_" + A.Name + " != null)\r\n");
                cs.Append("                {\r\n");
                cs.Append("                    ");
                if (A.HasReturnValue == true)
                {
                    cs.Append("RetObj = ");
                }
                cs.Append("Outer.External_" + A.Name + "(");
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if (arg.IsReturnValue == false)
                    {
                        if (arg.Direction == "out")
                        {
                            cs.Append("out ");
                        }
                        if (arg.RelatedStateVar.AllowedStringValues != null)
                        {
                            cs.Append("e_");
                        }
                        cs.Append(arg.Name);
                        if (i < Args.Length - 1)
                        {
                            cs.Append(", ");
                        }
                    }
                }
                cs.Append(");\r\n");
                cs.Append("                }\r\n");
                cs.Append("                else\r\n");
                cs.Append("                {\r\n");
                cs.Append("                    ");
                if (A.HasReturnValue == true)
                {
                    cs.Append("RetObj = ");
                }
                cs.Append("Sink_" + A.Name + "(");
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if (arg.IsReturnValue == false)
                    {
                        if (arg.Direction == "out")
                        {
                            cs.Append("out ");
                        }
                        if (arg.RelatedStateVar.AllowedStringValues != null)
                        {
                            cs.Append("e_");
                        }
                        cs.Append(arg.Name);
                        if (i < Args.Length - 1)
                        {
                            cs.Append(", ");
                        }
                    }
                }
                cs.Append(");\r\n");
                cs.Append("                }\r\n");

                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if ((arg.IsReturnValue == false) &&
                        (arg.RelatedStateVar.AllowedStringValues != null))
                    {
                        if (arg.Direction == "out")
                        {
                            cs.Append("                switch(e_" + arg.Name + ")\r\n");
                            cs.Append("                {\r\n");
                            vd = (VarData)elist[arg.RelatedStateVar.Name];
                            foreach (EnumStruct ss in vd.Enumerations)
                            {
                                cs.Append("                    case Enum_" + arg.RelatedStateVar.Name + "." + ss.EnumName + ":\r\n");
                                cs.Append("                        " + arg.Name + " = \"" + ss.EnumValue + "\";\r\n");
                                cs.Append("                        break;\r\n");
                            }
                            cs.Append("                    default:\r\n");
                            cs.Append("                        " + arg.Name + " = \"\";\r\n");
                            cs.Append("                        break;\r\n");
                            cs.Append("                }\r\n");

                        }
                    }
                }

                if (A.HasReturnValue == true)
                {
                    cs.Append("                return((" + A.GetRetArg().RelatedStateVar.GetNetType().FullName + ")RetObj);\r\n");
                }
                cs.Append("            }\r\n");
            }

            cs.Append("\r\n");
            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("            public Delegate_" + A.Name + " Sink_" + A.Name + ";\r\n");
            }
            cs.Append("        }\r\n"); // End of Private Class

            // Build Constructor
            cs.Append("        public " + ClassName + "()\r\n");
            cs.Append("        {\r\n");
            cs.Append("            _S = new _" + ClassName + "(this);\r\n");
            foreach (UPnPStateVariable V in SV)
            {
                cs.Append("            _S.GetUPnPService().GetStateVariableObject(\"" + V.Name + "\").OnModified += new UPnPStateVariable.ModifiedHandler(OnModifiedSink_" + V.Name + ");\r\n");
            }
            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("            _S.Sink_" + A.Name + " = new Delegate_" + A.Name + "(" + A.Name + ");\r\n");
            }

            cs.Append("        }\r\n");
            cs.Append("        public " + ClassName + "(string ID):this()\r\n");
            cs.Append("        {\r\n");
            cs.Append("            _S.GetUPnPService().ServiceID = ID;\r\n");
            cs.Append("        }\r\n");
            cs.Append("        public UPnPService GetUPnPService()\r\n");
            cs.Append("        {\r\n");
            cs.Append("            return(_S.GetUPnPService());\r\n");
            cs.Append("        }\r\n");
            foreach (UPnPStateVariable V in SV)
            {
                cs.Append("        private void OnModifiedSink_" + V.Name + "(UPnPStateVariable sender, object NewValue)\r\n");
                cs.Append("        {\r\n");
                cs.Append("            if (OnStateVariableModified_" + V.Name + " != null) OnStateVariableModified_" + V.Name + "(this);\r\n");
                cs.Append("        }\r\n");
            }
            cs.Append("        //}}}}} End of Code Block\r\n\r\n");
            cs.Append("        #endregion\r\n");
            cs.Append("\r\n");

            foreach (UPnPAction A in s.Actions)
            {
                cs.Append("        /// <summary>\r\n");
                cs.Append("        /// Action: " + A.Name + "\r\n");
                cs.Append("        /// </summary>\r\n");
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if (arg.IsReturnValue == false)
                    {
                        cs.Append("        /// <param name=\"" + arg.Name + "\">Associated State Variable: " + arg.RelatedStateVar.Name + "</param>\r\n");
                    }
                }
                if (A.HasReturnValue == true)
                {
                    cs.Append("        /// <returns>Associated StateVariable: " + A.GetRetArg().RelatedStateVar.Name + "</returns>\r\n");
                }
                cs.Append("        public ");
                if (A.HasReturnValue == false)
                {
                    cs.Append("void ");
                }
                else
                {
                    cs.Append(A.GetRetArg().RelatedStateVar.GetNetType().FullName + " ");
                }

                cs.Append(A.Name + "(");
                Args = A.ArgumentList;
                for (int i = 0; i < Args.Length; ++i)
                {
                    arg = Args[i];
                    if (arg.IsReturnValue == false)
                    {
                        if (arg.Direction == "out")
                        {
                            cs.Append("out ");
                        }

                        if (arg.RelatedStateVar.AllowedStringValues != null)
                        {
                            cs.Append("Enum_" + arg.RelatedStateVar.Name + " ");
                        }
                        else
                        {
                            cs.Append(arg.RelatedStateVar.GetNetType().FullName + " ");
                        }
                        cs.Append(arg.Name);
                        if (i < Args.Length - 1)
                        {
                            cs.Append(", ");
                        }
                    }
                }
                cs.Append(")" + cl);
                cs.Append("        {\r\n");
                cs.Append("            //ToDo: Add Your implementation here, and remove exception\r\n");
                cs.Append("            throw(new UPnPCustomException(800,\"This method has not been completely implemented...\"));\r\n");
                cs.Append("        }\r\n");
            }

            cs.Append("    }\r\n");
            cs.Append("}");

            UTF8Encoding UTF8 = new UTF8Encoding();
            FileStream ws = new FileStream(SavePath, FileMode.Create, FileAccess.Write);
            byte[] buffer = UTF8.GetBytes(cs.ToString());
            ws.Write(buffer, 0, buffer.Length);
            ws.Close();
        }
        protected static void PopulateActionStructs(CodeProcessor cs, UPnPDevice d, Hashtable VarTable)
        {
            foreach(UPnPDevice ed in d.EmbeddedDevices)
            {
                PopulateActionStructs(cs,ed,VarTable);
            }
            foreach(UPnPService s in d.Services)
            {
                cs.Append("struct UPnP_ActionTable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+" UPnP_ActionTable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_Impl = "+cs.NewLine);
                cs.Append("{"+cs.NewLine);
                string stringX;
                int stringXLen;
                StringBuilder sb = new StringBuilder();
                StringWriter SW = new StringWriter(sb);
                XmlTextWriter X = new XmlTextWriter(SW);

                foreach(UPnPAction a in s.Actions)
                {
                    UPnPDebugObject dobj = new UPnPDebugObject(a);
                    dobj.InvokeNonStaticMethod("GetXML",new object[1]{X});
                }
                X.Flush();
                InjectCompressedString(out stringX,out stringXLen,sb.ToString(),cs.NewLine);
                cs.Append("	"+stringX+","+cs.NewLine);
                cs.Append("	"+stringXLen.ToString()+","+cs.NewLine);
                cs.Append("	"+sb.Length.ToString()+cs.NewLine);
                cs.Append("};"+cs.NewLine);

                foreach(UPnPAction a in s.Actions)
                {
                    Hashtable t = (Hashtable)VarTable[s];

                    cs.Append("struct UPnP_Action_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_"+a.Name+" UPnP_Action_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_"+a.Name+"_Impl = "+cs.NewLine);
                    cs.Append("{"+cs.NewLine);
                    cs.Append("	"+((object[])t[a])[0].ToString()+","+cs.NewLine);
                    cs.Append("	"+((object[])t[a])[1].ToString()+cs.NewLine);
                    cs.Append("};"+cs.NewLine);
                }
            }
        }
        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;
        }
        protected static void PopulateStateVariableStructs(CodeProcessor cs, UPnPDevice d, Hashtable VarTable)
        {
            foreach(UPnPDevice ed in d.EmbeddedDevices)
            {
                PopulateStateVariableStructs(cs,ed,VarTable);
            }
            foreach(UPnPService s in d.Services)
            {
                cs.Append("struct UPnP_StateVariableTable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+" UPnP_StateVariableTable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_Impl = "+cs.NewLine);
                cs.Append("{"+cs.NewLine);
                string stringX;
                int stringXLen;
                StringBuilder sb = new StringBuilder();
                StringWriter SW = new StringWriter(sb);
                XmlTextWriter X = new XmlTextWriter(SW);

                foreach(UPnPStateVariable v in s.GetStateVariables())
                {
                    UPnPDebugObject dobj = new UPnPDebugObject(v);
                    dobj.InvokeNonStaticMethod("GetStateVariableXML",new object[1]{X});
                }
                X.Flush();
                InjectCompressedString(out stringX,out stringXLen,sb.ToString(),cs.NewLine);
                cs.Append("	"+stringX+","+cs.NewLine);
                cs.Append("	"+stringXLen.ToString()+","+cs.NewLine);
                cs.Append("	"+sb.Length.ToString()+cs.NewLine);
                cs.Append("};"+cs.NewLine);

                foreach(UPnPStateVariable v in s.GetStateVariables())
                {
                    Hashtable t = (Hashtable)VarTable[s];
                    int startingIndex = (int)((object[])t[v])[0];
                    string varString = (string)((object[])t[v])[2];

                    cs.Append("struct UPnP_StateVariable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_"+v.Name+" UPnP_StateVariable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_"+v.Name+"_Impl = "+cs.NewLine);
                    cs.Append("{"+cs.NewLine);
                    cs.Append("	"+startingIndex.ToString()+","+cs.NewLine); // Start Index
                    cs.Append("	"+(varString.IndexOf("</dataType>")+11).ToString()+","+cs.NewLine);

                    if (v.AllowedStringValues!=null)
                    {
                        int avlen=0;
                        foreach(string avs in v.AllowedStringValues)
                        {
                            avlen += avs.Length;
                        }
                        cs.Append("	"+(varString.IndexOf("<allowedValueList>")+startingIndex).ToString()+","+cs.NewLine); // Start of Allowed Value List
                        cs.Append("	18,"+cs.NewLine); // Length of allowedValueList
                        cs.Append("	"+(varString.IndexOf("</allowedValueList>")+startingIndex).ToString()+","+cs.NewLine); // Start of endTag
                        cs.Append("	19,"+cs.NewLine); // Length of end tag
                        cs.Append("	{");
                        foreach(string av in v.AllowedStringValues)
                        {
                            cs.Append("\""+av+"\",");
                        }
                        cs.Append("NULL");
                        cs.Append("}");
                    }
                    if (v.Minimum!=null || v.Maximum!=null)
                    {
                        if (v.AllowedStringValues!=null)
                        {
                            cs.Append(","+cs.NewLine);
                        }

                        cs.Append("	"+(startingIndex+varString.IndexOf("<allowedValueRange>")).ToString()+","+cs.NewLine);
                        cs.Append("	19,"+cs.NewLine);
                        cs.Append("	"+(startingIndex+varString.IndexOf("</allowedValueRange>")).ToString()+","+cs.NewLine);
                        cs.Append("	20,"+cs.NewLine);
                        cs.Append("	{");
                        if (v.Minimum!=null)
                        {
                            cs.Append("\""+v.Minimum.ToString()+"\",");
                        }
                        else
                        {
                            cs.Append("NULL,");
                        }
                        if (v.Maximum!=null)
                        {
                            cs.Append("\""+v.Maximum.ToString()+"\",");
                        }
                        else
                        {
                            cs.Append("NULL,");
                        }
                        if (v.Step!=null)
                        {
                            cs.Append("\""+v.Step.ToString()+"\"");
                        }
                        else
                        {
                            cs.Append("NULL");
                        }
                        cs.Append("}");
                    }
                    if (v.DefaultValue!=null)
                    {
                        if (v.AllowedStringValues!=null || v.Maximum!=null || v.Maximum!=null)
                        {
                            cs.Append(","+cs.NewLine);
                        }
                        cs.Append("	"+(startingIndex+varString.IndexOf("<defaultValue>")).ToString()+","+cs.NewLine);
                        cs.Append("	14,"+cs.NewLine);
                        cs.Append("	"+(startingIndex+varString.IndexOf("</defaultValue>")).ToString()+","+cs.NewLine);
                        cs.Append("	15,"+cs.NewLine);
                        cs.Append("\""+UPnPService.SerializeObjectInstance(v.DefaultValue)+"\"");
                    }
                    if (v.DefaultValue!=null || v.AllowedStringValues!=null || v.Maximum!=null || v.Maximum!=null)
                    {
                        cs.Append(","+cs.NewLine);
                    }
                    cs.Append((varString.IndexOf("</stateVariable>")+startingIndex).ToString()+","+cs.NewLine);
                    cs.Append("	16"+cs.NewLine);

                    cs.Append("};"+cs.NewLine);
                }
            }
        }
        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 static void BuildStateVariableStructs(CodeProcessor cs, UPnPDevice d)
        {
            foreach(UPnPDevice ed in d.EmbeddedDevices)
            {
                BuildStateVariableStructs(cs,ed);
            }
            foreach(UPnPService s in d.Services)
            {
                string stringX;
                int stringXLen;
                StringBuilder sb = new StringBuilder();
                StringWriter SW = new StringWriter(sb);
                XmlTextWriter X = new XmlTextWriter(SW);

                foreach(UPnPStateVariable v in s.GetStateVariables())
                {
                    UPnPDebugObject dobj = new UPnPDebugObject(v);
                    dobj.InvokeNonStaticMethod("GetStateVariableXML",new object[1]{X});
                }
                InjectCompressedString(out stringX,out stringXLen,sb.ToString(),cs.NewLine);

                cs.Append("struct UPnP_StateVariableTable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+cs.NewLine);
                cs.Append("{"+cs.NewLine);
                cs.Append("	char Reserved["+stringXLen.ToString()+"];"+cs.NewLine);
                cs.Append("	int ReservedXL;"+cs.NewLine);
                cs.Append("	int ReservedUXL;"+cs.NewLine);
                cs.Append("};"+cs.NewLine);

                foreach(UPnPStateVariable v in s.GetStateVariables())
                {
                    cs.Append("struct UPnP_StateVariable_"+((ServiceGenerator.ServiceConfiguration)s.User).Name+"_"+v.Name+cs.NewLine);
                    cs.Append("{"+cs.NewLine);
                    cs.Append("	int Reserved1;"+cs.NewLine);
                    cs.Append("	int Reserved1L;"+cs.NewLine);
                    if (v.AllowedStringValues!=null)
                    {
                        cs.Append("	int Reserved2;"+cs.NewLine);
                        cs.Append("	int Reserved2L;"+cs.NewLine);
                        cs.Append("	int Reserved3;"+cs.NewLine);
                        cs.Append("	int Reserved3L;"+cs.NewLine);
                        cs.Append("	char *AllowedValues[UPnP_StateVariable_AllowedValues_MAX];"+cs.NewLine);
                    }
                    if (v.Minimum!=null || v.Maximum!=null)
                    {
                        cs.Append("	int Reserved4;"+cs.NewLine);
                        cs.Append("	int Reserved4L;"+cs.NewLine);
                        cs.Append("	int Reserved5;"+cs.NewLine);
                        cs.Append("	int Reserved5L;"+cs.NewLine);
                        cs.Append("	char *MinMaxStep[3];"+cs.NewLine);
                    }
                    if (v.DefaultValue!=null)
                    {
                        cs.Append("	int Reserved6;"+cs.NewLine);
                        cs.Append("	int Reserved6L;"+cs.NewLine);
                        cs.Append("	int Reserved7;"+cs.NewLine);
                        cs.Append("	int Reserved7L;"+cs.NewLine);
                        cs.Append("	char *DefaultValue;"+cs.NewLine);
                    }
                    cs.Append("	int Reserved8;"+cs.NewLine);
                    cs.Append("	int Reserved8L;"+cs.NewLine);
                    cs.Append("};"+cs.NewLine);
                }
            }
        }
        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);
            }
        }
        protected static void GenerateStateVariableLookupTable_Service(UPnPService s, Hashtable t)
        {
            Hashtable lookupTable = new Hashtable();
            t[s] = lookupTable;

            int i=0;

            foreach(UPnPStateVariable v in s.GetStateVariables())
            {
                StringBuilder sb = new StringBuilder();
                StringWriter SW = new StringWriter(sb);
                XmlTextWriter X = new XmlTextWriter(SW);

                UPnPDebugObject dobj = new UPnPDebugObject(v);
                dobj.InvokeNonStaticMethod("GetStateVariableXML",new object[1]{X});

                lookupTable[v] = new object[3]{i,sb.Length,sb.ToString()};
                i+=sb.Length;
            }
        }
        private void ProcessDevice(UPnPDevice device)
        {
            UPnPDevice d = UPnPDevice.CreateEmbeddedDevice(double.Parse(device.Version), Guid.NewGuid().ToString());
            d.FriendlyName = "*" + device.FriendlyName;
            d.Manufacturer = device.Manufacturer;
            d.ManufacturerURL = device.ManufacturerURL;
            d.ModelDescription = device.ModelDescription;
            d.ModelURL = device.ModelURL;
            d.DeviceURN = device.DeviceURN;
            UDNTable[device.UniqueDeviceName] = d;
            ReverseUDNTable[d.UniqueDeviceName] = device.UniqueDeviceName;

            foreach (UPnPService S in device.Services)
            {
                UPnPService S2 = (UPnPService)S.Clone();
                foreach (UPnPAction A in S2.Actions)
                {
                    A.ParentService = S2;
                    A.SpecialCase += new UPnPAction.SpecialInvokeCase(InvokeSink);
                }

                UPnPDebugObject dbg = new UPnPDebugObject(S2);

                dbg.SetField("SCPDURL", "_" + S2.ServiceID + "_scpd.xml");
                dbg.SetProperty("ControlURL", "_" + S2.ServiceID + "_control");
                dbg.SetProperty("EventURL", "_" + S2.ServiceID + "_event");
                d.AddService(S2);
            }
            ((UPnPDevice)UDNTable[device.ParentDevice.UniqueDeviceName]).AddDevice(d);

            foreach (UPnPDevice _ed in device.EmbeddedDevices)
            {
                ProcessDevice(_ed);
            }
        }