/// <summary>
        /// Split this up in to sections so I can more easliy re-use it in the future.
        /// </summary>
        /// <param name="className"></param>
        public static void Generate(string className, string outputAssemblyName, CompilerFlags flags, List <String> assemblies)
        {
            string prefix = (flags.IsAbstract ? ABSTRACT_PREFIX : String.Empty);

            //this *can* generate more than one entry
            ControlTree[] trees = GenerateTree(className, outputAssemblyName, assemblies);
            if (trees != null && trees.Length == 1)
            {
                ControlTree tree     = trees[0];
                string      s        = ClassGenerator(tree, flags);
                string      infill   = (flags.AppendDesignedToFilename ? ".Designer" : String.Empty); //add in the Designed
                string      fileName = System.IO.Path.Combine(flags.OutputPath, String.Format("{1}{0}Controller{2}.cs", tree.ClassName, prefix, infill));

                //added a check to see if file exists, otherwise we might get weird streaming issues
                //if it does, I delete it for now.
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }

                WriteFile(s, fileName);

                if (flags.CreateEmptyNonDesignedFile)
                {
                    string stubFileName = System.IO.Path.Combine(flags.OutputPath, String.Format("{1}{0}Controller.cs", tree.ClassName, prefix));
                    if (!System.IO.File.Exists(stubFileName))
                    {
                        WriteFile(CreateStubFile(tree, flags), stubFileName);
                    }
                }
            }
        }
        /// <summary>
        /// Creates a stub file with the same makeup of the main file
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        private static string CreateStubFile(ControlTree tree, CompilerFlags flags)
        {
            string prefix = (flags.IsAbstract ? ABSTRACT_PREFIX : String.Empty);

            StringBuilder code = new StringBuilder();

            code.AppendLine("/*This stub code was generated by the MvcFramework compiler, created by RatCow Soft - \r\n See http://code.google.com/p/ratcowsoftopensource/ */ \r\n\r\nusing System; \r\nusing System.Windows.Forms;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Reflection;\r\n\r\n//3rd Party\r\nusing RatCow.MvcFramework;\r\n");
            code.AppendFormat("namespace {0}\r\n", tree.NamespaceName);
            code.AppendLine("{");
            code.AppendFormat("\tinternal partial class {1}{0}Controller: BaseController<{0}>\r\n", tree.ClassName, prefix);
            code.AppendLine("\t{");
            code.AppendLine("\t}");
            code.AppendLine("}");

            return(code.ToString());
        }
Ejemplo n.º 3
0
        private static void Main(string[] args)
        {
            //System.Diagnostics.Debugger.Break(); //Use this for force debugging
            XmlConfigurator.Configure(new System.IO.FileInfo("mvctool.exe.config"));

            CompilerFlags flags = new CompilerFlags(_log);

            //generate a list of assemblies in the associated mvcmap
            var assemblies = new List <String>();

            string className = null;

            //This is new - we try to interpret the compiler params
            if (args.Length == 0)
            {
                Console.WriteLine("USAGE - mvctool [options] classname");
                Console.WriteLine("\r\nOPTIONS:");
                Console.WriteLine(" --abstract / -a : prefix controllers with \"Abstract\" prefix");
                Console.WriteLine(" --partial-methods / -p : use partial methods (.Net 3.5+)");
                Console.WriteLine(" -e : send the controller to event handlers");
                Console.WriteLine(" -v : add pad code to protect list views");
                Console.WriteLine(" -c : create a new action config file called \"default.mvcmap\" (this can't be used with any other params)");
                Console.WriteLine(" -C : create a new action config file with view name passed (this can't be used with any other params)");
                Console.WriteLine(" -r : use the default mvcmap when creating actions");
                Console.WriteLine(" -R : use the mvcmap with the same name as the form passed when creating actions");
                Console.WriteLine(" -d : append the .Designer tag to the file name (e.g. Form1.Designer.cs)");
                Console.WriteLine(" -D : same as -d, but also creates a stub file if one doesn't exist.");
                Console.WriteLine(" -I : The location of the files to process. e.g. -I=c:\\projects\\views");
                Console.WriteLine(" -O : The location of where the files are to be put.  e.g. -I=c:\\projects\\controllers");
                //Console.WriteLine( " -i : ignore any RESX file in the same scope (do not link resources)" );
                Console.WriteLine();
                return;
            }
            else if (args.Length > 1)
            {
                bool foundFormName = false;

                if (args[0].Contains("-C"))
                {
                    CreateNewActionConfig(String.Format("{0}.mvcmap", args[1]));
                    return;
                }

                foreach (string arg in args)
                {
                    Console.WriteLine(arg);
                    Log.Debug(arg);

                    if (arg.StartsWith("-"))
                    {
                        Log.DebugFormat("Parsing param : {0}", arg);
                        //assume it's a param
                        if (arg.Contains("-a"))
                        {
                            flags.IsAbstract = true; //okay, this is a bit of a cheat
                        }
                        if (arg.Contains("-p"))
                        {
                            flags.UsePartialMethods = true;
                        }
                        if (arg.Contains("-e"))
                        {
                            flags.PassControllerToEvents = true;
                        }
                        if (arg.Contains("-v"))
                        {
                            flags.ProtectListViews = true;
                        }
                        if (arg.Contains("-r"))
                        {
                            flags.RestrictActions       = true;
                            flags.UseDefaultActionsFile = true;
                        }
                        if (arg.Contains("-d"))
                        {
                            flags.AppendDesignedToFilename = true;
                        }
                        if (arg.Contains("-D"))
                        {
                            flags.AppendDesignedToFilename   = true;
                            flags.CreateEmptyNonDesignedFile = true;
                        }
                        if (arg.Contains("-R"))
                        {
                            flags.RestrictActions = true;
                            //flags.UseDefaultActionsFile = false; //this should default to false...
                        }
                        if (arg.StartsWith("-i="))
                        {
                            string[] list = new StringBuilder(arg).Replace("-i=", String.Empty).Replace("\"", String.Empty).ToString().Split(',');
                            assemblies.AddRange(list);
                        }
                        if (arg.StartsWith("-I="))
                        {
                            flags.InputPath = arg.Replace("-I=", String.Empty);
                        }
                        if (arg.StartsWith("-O="))
                        {
                            flags.OutputPath = arg.Replace("-O=", String.Empty);
                        }
                    }
                    else
                    {
                        //assume it's the form name
                        if (foundFormName)
                        {
                            var s = String.Format("Did not understand \"{0}\", already found \"{1}\", ignoring.", className, arg);
                            Console.WriteLine(s);
                            Log.Error(s);
                        }
                        else
                        {
                            if (arg.Contains(System.IO.Path.DirectorySeparatorChar))
                            {
                                className = arg.Substring(arg.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1);
                                if (className.Contains("."))
                                {
                                    className = className.Remove(className.IndexOf("."));
                                }
                            }
                            else
                            {
                                className = arg;
                            }
                            foundFormName = true;
                            Log.DebugFormat("Found {0}", className);
                        }
                    }
                }

                Console.WriteLine(flags);
                Log.Debug(flags);

                if (!foundFormName)
                {
                    Console.WriteLine("Could not find the form name in the params! Aborted");
                    Log.Error("Could not find the form name in the params! Aborted");
                    return;
                }
            }
            else if (args.Length == 1 && args[0].Contains("-c"))
            {
                Log.Debug("Creating default.mvcmap");
                CreateNewActionConfig("default.mvcmap");
                return;
            }
            else //assume one param is form name
            {
                //this fixes a bug where user was unable to create a non abstract controller
                flags.IsAbstract             = false;
                flags.UsePartialMethods      = false;
                flags.PassControllerToEvents = false;
                flags.ProtectListViews       = false;
                className = args[0];
            }

            string outputAssemblyName = String.Format("{0}_{1}.dll", className, DateTime.Now.Ticks);

            Log.Debug(outputAssemblyName);



            //we currently assume this is one param and that is the name of the class
            //we also assume the files will be named in a standard C# naming convention.
            //i.e. MainForm -> MainForm.Designer.cs
            Log.Debug("Compiling class bootstrap");
            if (ControllerCreationEngine.Compile(className, outputAssemblyName, flags, assemblies))
            {
                Log.Debug("Generating code");
                //if we get here, we created the desired assembly above
                ControllerCreationEngine.Generate(className, outputAssemblyName, flags, assemblies);
                Log.Debug("Successfully generated code");
            }
            else
            {
                Console.WriteLine("Error! The file could not be generated.");
                Log.Error("Error! The file could not be generated.");
                return;
            }

            //Console.ReadLine(); //DEBUG - stop app before close
        }
        /// <summary>
        /// This adds is a standard hook for the ListView and creates a ListViewHelper attached to it.
        /// </summary>
        /// <param name="controlName"></param>
        /// <param name="hook"></param>
        /// <param name="action"></param>
        private static void AddListViewHandler(string controlName, StringBuilder hook, StringBuilder action, CompilerFlags flags)
        {
            hook.AppendFormat("\t\tprotected ListViewHelper<T> Get{0}Helper<T>() where T : class\r\n", controlName);
            hook.AppendLine("\t\t{\r\n\t\t\t//Auto generated call");

            hook.AppendFormat("\t\t\tvar lvh = new ListViewHelper<T>({0});\r\n", controlName);
            hook.AppendLine("\t\t\treturn lvh;");

            hook.AppendLine("\t\t}\r\n");

            //add in the handler for the virtual list item

            hook.AppendFormat("\t\t[Action(\"{0}\", \"RetrieveVirtualItem\")]\r\n\t\tpublic void F{0}_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)\r\n", controlName);
            hook.AppendLine("\t\t{\r\n\t\t\t//Auto generated call");

            action.AppendFormat("\t\tprotected virtual void {0}RetrieveVirtualItem(RetrieveVirtualItemEventArgs e)\r\n", controlName); //added "protected virtual" so that I can descend and not have to alter this class at all.
            action.AppendLine("\t\t{");

            action.AppendLine("\t\t\t/*we will first try to get an item from the partial method*/");
            action.AppendLine("\t\t\tListViewItem item = null; //set to a known value");

            if (flags.UsePartialMethods)
            {
                action.AppendFormat("\t\t\t{0}GetItem(ref item, e); //try to get the value from partial implementation\r\n", controlName);
            }

            if (flags.ProtectListViews)
            {
                action.AppendLine("\t\t\tif (item == null) //if, null, save ourselves from crashing \r\n\t\t\t{");
                action.AppendLine("\t\t\t/*default placeholder to avoid crashes*/\r\n\t\t\titem = new ListViewItem();\r\n");
                action.AppendLine("\t\t\t/*we need to provide a value for each column*/");
                action.AppendFormat("\t\t\tint count = ({0}.Columns.Count);\r\n", controlName);
                action.AppendLine("\t\t\tif (count > 1)\r\n\t\t\t{");
                action.AppendLine("\t\t\t\titem.Text = \"Temp value\";");
                action.AppendLine("\t\t\t\tfor (int i = 1; i < count; i++)\r\n\t\t\t\t{");
                action.AppendLine("\t\t\t\t\titem.SubItems.Add(\"Temp Subitem\");\r\n\t\t\t\t}\t\r\n\t\t\t}\r\n\t\t}");
            }

            action.AppendLine("\r\n\t\t\te.Item = item;");

            action.AppendLine("\t\t}\r\n");

            hook.AppendFormat("\t\t\t{0}RetrieveVirtualItem(e);\r\n", controlName);

            hook.AppendLine("\t\t}\r\n");

            if (flags.UsePartialMethods)
            {
                action.AppendFormat(
                    "\t\tpartial void {0}GetItem(ref ListViewItem item, RetrieveVirtualItemEventArgs e);\r\n",
                    controlName
                    );
            }
        }
        /// <summary>
        /// Create generic event hooks
        /// </summary>
        private static void AddAction(string viewName, string controlName, string actionName, string eventArgsType, StringBuilder hook, StringBuilder action, CompilerFlags flags)
        {
            //DEBUG - Console.WriteLine("{0}Controller :: {1} :: {2} - -a : {3} -p : {4} -e : {5} -v : {6}", viewName, controlName, actionName, flags.IsAbstract, flags.UsePartialMethods, flags.PassControllerToEvents, flags.ProtectListViews);

            hook.AppendFormat("\t\t[Action(\"{0}\", \"{1}\")]\r\n\t\tpublic void F{0}_{1}(object sender, {2} e)\r\n", controlName, actionName, eventArgsType);
            hook.AppendLine("\t\t{\r\n\t\t\t//Auto generated call");

            action.AppendFormat(
                "\t\t{2} void {0}{1}({4}{5} e){3}\r\n",
                controlName,
                actionName,
                (flags.UsePartialMethods ? "partial" : "protected virtual"),
                (flags.UsePartialMethods ? ";" : String.Empty),
                (flags.PassControllerToEvents ? String.Format("{0}Controller controller,", viewName) : String.Empty),
                eventArgsType
                );
            //added "protected virtual" so that I can descend and not have to alter this class at all.
            //20120529 - added partial method option for 3.5+

            if (!flags.UsePartialMethods)
            {
                action.AppendLine("\t\t{\r\n");
                action.AppendLine("\t\t}\r\n");
            }//20120529 - added partial method option for 3.5+

            hook.AppendFormat("\t\t\t{0}{1}({2}e);\r\n", controlName, actionName, (flags.PassControllerToEvents ? "this, " : String.Empty));

            hook.AppendLine("\t\t}\r\n");
        }
 /// <summary>
 /// KeyEventHandler stub.
 /// </summary>
 private static void AddKeyAction(string viewName, string controlName, string actionName, StringBuilder hook, StringBuilder action, CompilerFlags flags)
 {
     AddAction(viewName, controlName, actionName, "KeyEventArgs", hook, action, flags);
 }
        /// <summary>
        /// This is going to initially be fairly slow
        /// </summary>
        private static void AddMappedActions(string viewName, KeyValuePair <string, Type> control, StringBuilder hook, StringBuilder action, CompilerFlags flags, ViewActionMap map)
        {
            var added = new List <String>(); //tally, to avoid double adds

            //we first add the generic stuff
            foreach (var ev in map.GlobalMap)
            {
                if (!added.Contains(ev.EventName))
                {
                    //does the event exist?
                    var evi = control.Value.GetEvent(ev.EventName);

                    if (evi == null)
                    {
                        continue;
                    }
                    else
                    {
                        AddAction(viewName, control.Key, ev.EventName, ev.EventArgsName, hook, action, flags);
                        added.Add(ev.EventName);
                    }
                }
            }

            //IEnumerable<ViewControlAction> controlMapItems = map.ControlActionMap.F(ev => ev.ControlType == control.Value.Name);
            var controlMapItems = from item in map.ControlActionMap
                                  where (item.ControlType == control.Value.Name || item.ControlType == control.Value.FullName) //this seems like a good idea, probably a bug since we extended the controlmaps to use the full name for non System.Windows.Forms controls....?
                                  select item;

            if (controlMapItems == null)
            {
                return;
            }
            else
            {
                foreach (var controlMap in controlMapItems)
                {
                    if (controlMap != null)
                    {
                        foreach (var ev in controlMap.ControlActions)
                        {
                            //this has to be here
                            if (!added.Contains(ev.EventName))
                            {
                                AddAction(viewName, control.Key, ev.EventName, ev.EventArgsName, hook, action, flags);
                                added.Add(ev.EventName);
                            }
                        }
                    }
                }
            }
        }
 /// <summary>
 /// Start to implement generic event handling
 /// </summary>
 private static void AddKnownActions(string viewName, KeyValuePair <string, Type> control, StringBuilder hook, StringBuilder action, CompilerFlags flags)
 {
     //test - get a list of all the events for this control
     EventInfo[] eva = control.Value.GetEvents();
     foreach (var ev in eva)
     {
         //generally, the event is XXXXEvent and the args are XXXXArgs..
         //TODO: look at making htis more generic.. can we get at the param info for the delegate?
         if (ev.EventHandlerType == typeof(System.EventHandler))
         {
             AddStandardAction(viewName, control.Key, ev.Name, hook, action, flags);
         }
         else if (ev.EventHandlerType == typeof(System.Windows.Forms.MouseEventHandler))
         {
             AddMouseAction(viewName, control.Key, ev.Name, hook, action, flags);
         }
         else if (ev.EventHandlerType == typeof(System.Windows.Forms.KeyEventHandler))
         {
             AddKeyAction(viewName, control.Key, ev.Name, hook, action, flags);
         }
         else if (ev.EventHandlerType == typeof(System.Windows.Forms.DragEventHandler))
         {
             AddDragAction(viewName, control.Key, ev.Name, hook, action, flags);
         }
         //could add an else clause to create a theoretical event arg from the handler name here...
     }
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="isAbstract"></param>
        /// <returns></returns>
        public static string ClassGenerator(ControlTree tree, CompilerFlags flags)
        {
            string prefix = (flags.IsAbstract ? ABSTRACT_PREFIX : String.Empty);

            StringBuilder code = new StringBuilder();

            code.AppendLine("/*Auto generated - this code was generated by the MvcFramework compiler, created by RatCow Soft - \r\n See http://code.google.com/p/ratcowsoftopensource/ */ \r\n\r\nusing System; \r\nusing System.Windows.Forms;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Reflection;\r\n\r\n//3rd Party\r\nusing RatCow.MvcFramework;\r\n");
            code.AppendFormat("namespace {0}\r\n", tree.NamespaceName);
            code.AppendLine("{");

            StringBuilder code_s1 = new StringBuilder();

            if (flags.CreateEmptyNonDesignedFile)
            {
                //if we are creating a stub, we should put the inheritence in the stub, to allow it to be altered (e.g. modal)
                code_s1.AppendFormat("\tinternal partial class {1}{0}Controller\r\n", tree.ClassName, prefix);
            }
            else
            {
                code_s1.AppendFormat("\tinternal partial class {1}{0}Controller: BaseController<{0}>\r\n", tree.ClassName, prefix);
            }
            code_s1.AppendLine("\t{");

            //constructor
            code_s1.AppendFormat("\t\tpublic {1}{0}Controller() : base()\r\n", tree.ClassName, prefix);
            code_s1.AppendLine("\t\t{\r\n\t\t}\r\n");

            StringBuilder code_s2 = new StringBuilder();

            code_s2.AppendLine("\r\n#region GUI glue code\r\n");
            code_s2.AppendFormat("\tpartial class {1}{0}Controller\r\n", tree.ClassName, prefix);
            code_s2.AppendLine("\t{");

            if (flags.RestrictActions)
            {
                //load the actions file
                ViewActionMap map = (flags.UseDefaultActionsFile ? GetDefaultViewActionMap() : GetNamedViewActionMap(tree.ClassName, true));

                //we now have access to the controls
                foreach (var control in tree.Controls)
                {
                    //System.Console.WriteLine(" var {0} : {1} ", control.Name, control.GetType().Name);
                    //add the declaration to code_s2
                    code_s2.AppendFormat("\t\t[Outlet(\"{1}\")]\r\n\t\tpublic {0} {1} ", control.Value.FullName, control.Key); //add var
                    code_s2.AppendLine("{ get; set; }");

                    //this should find all known event types
                    AddMappedActions(tree.ClassName, control, code_s2, code_s1, flags, map);

                    //specific listView hooks
                    if (control.Value == typeof(System.Windows.Forms.ListView))
                    {
                        AddListViewHandler(control.Key, code_s2, code_s1, flags);
                    }
                }
            }
            else
            {
                //we now have access to the controls
                foreach (var control in tree.Controls)
                {
                    //System.Console.WriteLine(" var {0} : {1} ", control.Name, control.GetType().Name);
                    //add the declaration to code_s2
                    code_s2.AppendFormat("\t\t[Outlet(\"{1}\")]\r\n\t\tpublic {0} {1} ", control.Value.FullName, control.Key); //add var
                    code_s2.AppendLine("{ get; set; }");

                    //this should find all known event types
                    AddKnownActions(tree.ClassName, control, code_s2, code_s1, flags);

                    //specific listView hooks
                    if (control.Value == typeof(System.Windows.Forms.ListView))
                    {
                        AddListViewHandler(control.Key, code_s2, code_s1, flags);
                    }
                }
            }

            //some boiler plate code which helps set the data for a LisViewHelper

            code_s2.AppendLine("\t\tprotected void SetData<T>(ListViewHelper<T> helper, List<T> data) where T : class");
            code_s2.AppendLine("\t\t{\r\n\t\t\t//Auto generated call");

            code_s2.AppendLine("\t\t\tType t = helper.GetType();");
            code_s2.AppendLine("\t\t\tt.InvokeMember(\"SetData\", BindingFlags.Default | BindingFlags.InvokeMethod, null, helper, new object[] { data });");

            code_s2.AppendLine("\t\t}\r\n");

            code_s1.AppendLine("\t}"); //end of class declaration
            code.AppendLine(code_s1.ToString());

            code_s2.AppendLine("\t}"); //end of class declaration
            code_s2.AppendLine("#endregion /*GUI glue code*/");
            code.AppendLine(code_s2.ToString());

            code.AppendLine("}");

            return(code.ToString());
        }
        /// <summary>
        /// Hacked mini compiler - it does enough to compile *basic* designer classes
        /// </summary>
        /// <param name="className"></param>
        /// <returns></returns>
        public static bool Compile(string className, string outputAssemblyName, CompilerFlags flags, List <String> extraAssemblies)
        {
            flags.LogDebug("Enter Compile");

            //we attempt to compile the file provided and then read info from it
            CSharpCodeProvider compiler       = new CSharpCodeProvider();
            CompilerParameters compilerParams = new CompilerParameters();

            compilerParams.ReferencedAssemblies.Add("System.dll");
            compilerParams.ReferencedAssemblies.Add("System.XML.dll");
            compilerParams.ReferencedAssemblies.Add("System.Data.dll");
            compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            compilerParams.ReferencedAssemblies.Add("System.Drawing.dll");

            foreach (var extraAssembly in extraAssemblies)
            {
                compilerParams.ReferencedAssemblies.Add(extraAssembly); //this takes the physical location
            }

            //we can add more in here from command line in future revision

            compilerParams.GenerateExecutable = false;
            compilerParams.CompilerOptions    = "/t:library";
            compilerParams.OutputAssembly     = outputAssemblyName; // "./temp.dll";

            StringBuilder s = new StringBuilder();

            string namespaceName = "";
            string fileToCompile = System.IO.Path.Combine(flags.InputPath, String.Format("{0}.Designer.cs", className));

            if (!File.Exists(fileToCompile))
            {
                return(false);
            }

            TextReader tr = new StreamReader(File.OpenRead(fileToCompile));

            try
            {
                //read till we find the namespace

                while (true)
                {
                    string t = tr.ReadLine();
                    s.Append(t);
                    if (t.Contains("namespace"))
                    {
                        namespaceName = t.Substring(10).Trim();
                        break;
                    }
                }

                s.Append(tr.ReadToEnd());
            }
            finally
            {
                tr.Close();
            }

            //This is a bit of a hack... we need the designer to be a "Form" so we can compile it and
            //then use the Activator to access the contents later on. We *have* to call "InitializeComponents()"
            //otherwise, the form is in an uninitialized state and we will not have access to the parts we
            //actually *want*.
            string code  = "{ public " + className + "(): base() { InitializeComponent();} public System.ComponentModel.IContainer ComponentsAccess {get { return components; } } } /*class*/   } /*namespace*/";
            string dummy = String.Format("namespace {2} {3} partial class {0} : System.Windows.Forms.Form {1}", className, code, namespaceName, "{");

            //we need to look for a resource file
            var resx = System.IO.Path.Combine(flags.InputPath, String.Format("{0}.resx", className));

            //string rescode = null;

            var compiledResourceFilename = System.IO.Path.Combine(flags.InputPath, String.Format("{0}.{1}.resources", namespaceName, className));


            //we should compile resource files by default!!
            if (!flags.IgnoreResourceFiles && File.Exists(resx))
            {
                //we must now open the resource file and read the contents
                try
                {
                    File.Delete(compiledResourceFilename); //remove older version
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    System.Diagnostics.Debug.WriteLine(ex.StackTrace);
                }

                //IDictionary dictionary = null;

                using (var stream = File.Open(resx, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    using (var rsxr = new ResXResourceReader(stream))
                    {
                        using (IResourceWriter writer = new ResourceWriter(compiledResourceFilename))
                        {
                            // Iterate through the resources and add resources to the resource writer.
                            //dictionary = new Dictionary<string, string>();
                            foreach (DictionaryEntry d in rsxr)
                            {
                                var k = d.Key.ToString();
                                var v = d.Value.ToString();

                                //dictionary.Add( k, v );
                                writer.AddResource(k, d.Value); //code example I used had this line as (k, v) which embeds a string resource rather than the real resource!!!
                            }
                            writer.Close();
                        }
                        rsxr.Close();
                    }

                    stream.Close();
                }

                compilerParams.EmbeddedResources.Add(compiledResourceFilename);

                #region Old

                //code example I used had this, but it seems to break the compilation if included
                //string[] errors;
                //var provider = new CSharpCodeProvider(); // c#-code compiler
                //var cu = StronglyTypedResourceBuilder.Create( dictionary, className ?? string.Empty, "", provider, false, out errors );

                //var options = new CodeGeneratorOptions
                //{
                //  BracingStyle = "C",
                //  BlankLinesBetweenMembers = false,
                //  IndentString = "\t"
                //};

                //var tw = new StringWriter();
                //provider.GenerateCodeFromCompileUnit( cu, tw, options );
                //rescode = tw.ToString();
                //tw.Close();

                #endregion
            }

            //The files to compile
            string[] files = { dummy, s.ToString() };

            //if ( rescode != null )
            //  files = new string[] { dummy, s.ToString(), rescode };
            //else
            //  files = new string[] { dummy, s.ToString() };

            CompilerResults res = null;
            try
            {
                res = compiler.CompileAssemblyFromSource(compilerParams, files);
            }

            catch (BadImageFormatException ex)
            {
                System.Console.WriteLine(ex.Message);
                return(false);
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex.Message);
                return(false);
            }
            if (res.Errors.HasErrors)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("\nIllegal C# source code generated: ");
                sb.Append(res.Errors.Count.ToString());
                sb.Append(" Errors:\n");
                foreach (CompilerError error in res.Errors)
                {
                    sb.Append("Line: ");
                    sb.Append(error.Line.ToString());
                    sb.Append(" - ");
                    sb.Append(error.ErrorText);
                    sb.Append('\n');
                }
                System.Console.WriteLine(sb.ToString());
                return(false);
            }

            //make sure we delete the resourse we created
            try
            {
                if (File.Exists(compiledResourceFilename))
                {
                    File.Delete(compiledResourceFilename);
                }
            }
            catch { } //we don't care, we just don't want to throw an exception here if we compiled a successful assembly

            flags.LogDebug("Leave Compile");
            return(true);
        }
Ejemplo n.º 11
0
        private static void Main(string[] args)
        {
            //System.Diagnostics.Debugger.Break(); //Use this for force debugging

            CompilerFlags flags = new CompilerFlags();

            string className = null;

            //This is new - we try to interpret the compiler params
            if (args.Length == 0)
            {
                Console.WriteLine("USAGE - mvctool [options] classname");
                Console.WriteLine("\r\nOPTIONS:");
                Console.WriteLine(" --abstract / -a : prefix controllers with \"Abstract\" prefix");
                Console.WriteLine(" --partial-methods / -p : use partial methods (.Net 3.5+)");
                Console.WriteLine(" -e : send the controller to event handlers");
                Console.WriteLine(" -v : add pad code to protect list views");
                Console.WriteLine(" -c : create a new action config file called \"default.mvcmap\" (this can't be used with any other params)");
                Console.WriteLine(" -C : create a new action config file with view name passed (this can't be used with any other params)");
                Console.WriteLine(" -r : use the default mvcmap when creating actions");
                Console.WriteLine(" -R : use the mvcmap with the same name as the form passed when creating actions");
                Console.WriteLine(" -d : append the .Designer tag to the file name (e.g. Form1.Designer.cs)");
                Console.WriteLine(" -D : same as -d, but also creates a stub file if one doesn't exist.");
                Console.WriteLine();
                return;
            }
            else if (args.Length > 1)
            {
                bool foundFormName = false;

                if (args[0].Contains("-C"))
                {
                    CreateNewActionConfig(String.Format("{0}.mvcmap", args[1]));
                    return;
                }

                foreach (string arg in args)
                {
                    Console.WriteLine(arg);

                    if (arg.StartsWith("-"))
                    {
                        //assume it's a param
                        if (arg.Contains("-a"))
                        {
                            flags.IsAbstract = true; //okay, this is a bit of a cheat
                        }
                        if (arg.Contains("-p"))
                        {
                            flags.UsePartialMethods = true;
                        }
                        if (arg.Contains("-e"))
                        {
                            flags.PassControllerToEvents = true;
                        }
                        if (arg.Contains("-v"))
                        {
                            flags.ProtectListViews = true;
                        }
                        if (arg.Contains("-r"))
                        {
                            flags.RestrictActions       = true;
                            flags.UseDefaultActionsFile = true;
                        }
                        if (arg.Contains("-d"))
                        {
                            flags.AppendDesignedToFilename = true;
                        }
                        if (arg.Contains("-D"))
                        {
                            flags.AppendDesignedToFilename   = true;
                            flags.CreateEmptyNonDesignedFile = true;
                        }
                        if (arg.Contains("-R"))
                        {
                            flags.RestrictActions = true;
                            //flags.UseDefaultActionsFile = false; //this should default to false...
                        }
                    }
                    else
                    {
                        //assume it's the form name
                        if (foundFormName)
                        {
                            Console.WriteLine(String.Format("Did not understand \"{0}\", already found \"{1}\", ignoring.", className, arg));
                        }
                        else
                        {
                            className     = arg;
                            foundFormName = true;
                        }
                    }
                }

                Console.WriteLine(flags);

                if (!foundFormName)
                {
                    Console.WriteLine("Could not find the form name in the params! Aborted");
                    return;
                }
            }
            else if (args.Length == 1 && args[0].Contains("-c"))
            {
                CreateNewActionConfig("default.mvcmap");
                return;
            }
            else //assume one param is form name
            {
                //this fixes a bug where user was unable to create a non abstract controller
                flags.IsAbstract             = false;
                flags.UsePartialMethods      = false;
                flags.PassControllerToEvents = false;
                flags.ProtectListViews       = false;
                className = args[0];
            }

            string outputAssemblyName = String.Format("{0}_{1}.dll", className, DateTime.Now.Ticks);

            //we currently assume this is one param and that is the name of the class
            //we also assume the files will be named in a standard C# naming convention.
            //i.e. MainForm -> MainForm.Designer.cs
            if (ControllerCreationEngine.Compile(className, outputAssemblyName))
            {
                //if we get here, we created the desired assembly above
                ControllerCreationEngine.Generate(className, outputAssemblyName, flags);
            }
            else
            {
                Console.WriteLine("Error! The file could not be generated.");
                return;
            }
        }