diff --git a/README.md b/README.md new file mode 100644 index 00000000..48ea2f61 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Hprose Invocation Proxy Implementation Generator + +Copyright (c) 2008-2016 http://hprose.com + +hipig -i:IExample.cs -r:Hprose.Client.dll -o:Example.cs + + -input:FILE1[,FILEn] Input files (short: -i) + -output:FILE Output files (short: -o) + -reference:A1[,An] Imports metadata from the specified assembly (short: -r) \ No newline at end of file diff --git a/example/IExample.cs b/example/IExample.cs new file mode 100644 index 00000000..985660ac --- /dev/null +++ b/example/IExample.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using Hprose.Common; +using System.Threading.Tasks; + +namespace Example { + public class User { + public string name; + public int age; + public bool male; + public List friends; + } + + public interface IExample { + [SimpleMode(true)] + Task Hello(string name); + [ResultMode(HproseResultMode.Serialized)] + [MethodName("SendUsers")] + byte[] SendUsersRaw(List users); + List SendUsers(List users); + void SendUsers(List users, HproseCallback1> callback); + } +} \ No newline at end of file diff --git a/hipig/hipig.sln b/hipig/hipig.sln new file mode 100644 index 00000000..0652ae5b --- /dev/null +++ b/hipig/hipig.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "hipig", "hipig\hipig.csproj", "{EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Debug|x86.ActiveCfg = Debug|x86 + {EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Debug|x86.Build.0 = Debug|x86 + {EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Release|x86.ActiveCfg = Release|x86 + {EBDF43B1-5BB4-495B-AE69-7FF5D548D84D}.Release|x86.Build.0 = Release|x86 + EndGlobalSection +EndGlobal diff --git a/hipig/hipig.userprefs b/hipig/hipig.userprefs new file mode 100644 index 00000000..18b66acc --- /dev/null +++ b/hipig/hipig.userprefs @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/hipig/hipig/Hprose.Client.dll b/hipig/hipig/Hprose.Client.dll new file mode 100644 index 00000000..1b27db9c Binary files /dev/null and b/hipig/hipig/Hprose.Client.dll differ diff --git a/hipig/hipig/Program.cs b/hipig/hipig/Program.cs new file mode 100644 index 00000000..06f7679d --- /dev/null +++ b/hipig/hipig/Program.cs @@ -0,0 +1,214 @@ +using System; +using Microsoft.CSharp; +using System.CodeDom.Compiler; +using System.Reflection; +using System.Text; +using System.CodeDom; +using System.IO; +using Hprose.Common; + +namespace Hprose { + class HIPIG { + public static CodeTypeDeclaration ImplementIt(Type it) { + string name = it.Name; + if (name.Length > 1 && name[0] == 'I' && name[1] >= 'A' && name[1] <= 'Z') { + name = name.Substring(1); + } + name += "Impl"; + CodeTypeDeclaration proxyClass = new CodeTypeDeclaration(name); + proxyClass.BaseTypes.Add(typeof(HproseInvocationHandler)); + proxyClass.BaseTypes.Add(it); + + CodeConstructor constructor = new CodeConstructor(); + constructor.Attributes = MemberAttributes.Public; + constructor.Parameters.Add( new CodeParameterDeclarationExpression(typeof(HproseInvoker), "invoker") ); + constructor.Parameters.Add( new CodeParameterDeclarationExpression(typeof(String), "ns") ); + constructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("invoker")); + constructor.BaseConstructorArgs.Add(new CodeVariableReferenceExpression("ns")); + proxyClass.Members.Add(constructor); + + CodeConstructor constructor2 = new CodeConstructor(); + constructor2.Attributes = MemberAttributes.Public; + constructor2.Parameters.Add( new CodeParameterDeclarationExpression(typeof(HproseInvoker), "invoker") ); + constructor2.ChainedConstructorArgs.Add(new CodeVariableReferenceExpression("invoker")); + constructor2.ChainedConstructorArgs.Add(new CodePrimitiveExpression("")); + proxyClass.Members.Add(constructor2); + + foreach (MethodInfo m in it.GetMethods()) { + CodeMemberMethod method = new CodeMemberMethod(); + method.Name = m.Name; + method.Attributes = MemberAttributes.Public; + ParameterInfo[] pis = m.GetParameters(); + foreach (ParameterInfo p in pis) { + CodeParameterDeclarationExpression cpde = new CodeParameterDeclarationExpression(p.ParameterType, p.Name); + if (p.IsOut) cpde.Direction = FieldDirection.Out; + if (p.ParameterType.IsByRef) cpde.Direction = FieldDirection.Ref; + method.Parameters.Add(cpde); + } + method.ReturnType = new CodeTypeReference(m.ReturnType); + + CodeExpression[] types = new CodeExpression[pis.Length]; + for (int i = 0; i < pis.Length; i++) { + types[i] = new CodeTypeOfExpression(pis[i].ParameterType); + } + + var customAttrs = m.GetCustomAttributes(true); + var n = 0; + foreach (var attr in customAttrs) { + if (attr is ResultModeAttribute || + attr is SimpleModeAttribute || + attr is ByRefAttribute || + attr is MethodNameAttribute) { + n++; + } + } + CodeExpression[] attrs = new CodeExpression[n]; + n = 0; + foreach (var attr in customAttrs) { + if (attr is ResultModeAttribute) { + attrs[n++] = new CodeObjectCreateExpression(typeof(ResultModeAttribute), new CodeSnippetExpression("HproseResultMode." + (attr as ResultModeAttribute).Value)); + } + else if (attr is SimpleModeAttribute) { + attrs[n++] = new CodeObjectCreateExpression(typeof(SimpleModeAttribute), new CodePrimitiveExpression((attr as SimpleModeAttribute).Value)); + } + else if (attr is ByRefAttribute) { + attrs[n++] = new CodeObjectCreateExpression(typeof(ByRefAttribute), new CodePrimitiveExpression((attr as ByRefAttribute).Value)); + } + else if (attr is MethodNameAttribute) { + attrs[n++] = new CodeObjectCreateExpression(typeof(MethodNameAttribute), new CodePrimitiveExpression((attr as MethodNameAttribute).Value)); + } + } + + CodeExpression[] args = new CodeExpression[pis.Length]; + for (int i = 0; i < pis.Length; i++) { + args[i] = new CodeVariableReferenceExpression(pis[i].Name); + } + if (m.ReturnType != typeof(void)) { + method.Statements.Add(new CodeMethodReturnStatement(new CodeCastExpression(method.ReturnType, new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Invoke", new CodeExpression[] { + new CodeThisReferenceExpression(), + new CodePrimitiveExpression(method.Name), + (types.Length == 0) ? new CodeArrayCreateExpression(typeof(Type[]), 0) : new CodeArrayCreateExpression(typeof(Type[]), types), + new CodeTypeOfExpression(method.ReturnType), + (attrs.Length == 0) ? new CodeArrayCreateExpression(typeof(Attribute[]), 0) : new CodeArrayCreateExpression(typeof(Attribute[]), attrs), + (args.Length == 0) ? new CodeArrayCreateExpression(typeof(object[]), 0) : new CodeArrayCreateExpression(typeof(object[]), args) + })))); + } + else { + method.Statements.Add(new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Invoke", new CodeExpression[] { + new CodeThisReferenceExpression(), + new CodePrimitiveExpression(method.Name), + (types.Length == 0) ? new CodeArrayCreateExpression(typeof(Type[]), 0) : new CodeArrayCreateExpression(typeof(Type[]), types), + new CodeTypeOfExpression(method.ReturnType), + (attrs.Length == 0) ? new CodeArrayCreateExpression(typeof(Attribute[]), 0) : new CodeArrayCreateExpression(typeof(Attribute[]), attrs), + (args.Length == 0) ? new CodeArrayCreateExpression(typeof(object[]), 0) : new CodeArrayCreateExpression(typeof(object[]), args) + })); + } + proxyClass.Members.Add(method); + } + return proxyClass; + } + public static void Main(string[] args) { + + if (args.Length == 0) { + Console.WriteLine("Hprose Invocation Proxy Implementation Generator 1.0"); + Console.WriteLine("Copyright (c) 2008-2016 http://hprose.com"); + Console.WriteLine("hipig -i:IExample.cs -r:Hprose.Client.dll -o:Example.cs"); + Console.WriteLine(" -input:FILE1[,FILEn] Input files (short: -i)"); + Console.WriteLine(" -output:FILE Output files (short: -o)"); + Console.WriteLine(" -reference:A1[,An] Imports metadata from the specified assembly (short: -r)"); + return; + } + CSharpCodeProvider objCSharpCodePrivoder = new CSharpCodeProvider(); + + CompilerParameters objCompilerParameters = new CompilerParameters(); + objCompilerParameters.ReferencedAssemblies.Add("mscorlib.dll"); + objCompilerParameters.ReferencedAssemblies.Add("System.dll"); + objCompilerParameters.ReferencedAssemblies.Add("System.Core.dll"); + + objCompilerParameters.GenerateExecutable = false; + objCompilerParameters.GenerateInMemory = true; + objCompilerParameters.OutputAssembly = ""; + + string[] inputFiles = null; + string output = "ServiceProxyImpl.cs"; + + foreach (string a in args) { + if (a.StartsWith("-r:") || a.StartsWith("-reference:")) { + string references = a.Substring(a.IndexOf(":") + 1); + if (references[0] == '"') references = references.Substring(1); + if (references[references.Length - 1] == '"') references = references.Substring(0, references.Length - 1); + objCompilerParameters.ReferencedAssemblies.AddRange(references.Split(',')); + } + if (a.StartsWith("-i:") || a.StartsWith("-input:")) { + string input = a.Substring(a.IndexOf(":") + 1); + if (input[0] == '"') input = input.Substring(1); + if (input[input.Length - 1] == '"') input = input.Substring(0, input.Length - 1); + inputFiles = input.Split(','); + } + if (a.StartsWith("-o:") || a.StartsWith("-output:")) { + output = a.Substring(a.IndexOf(":") + 1); + if (output[0] == '"') output = output.Substring(1); + if (output[output.Length - 1] == '"') output = output.Substring(0, output.Length - 1); + } + } + if (inputFiles == null) { + inputFiles = new string[] { args[0] }; + } + + CompilerResults cr = objCSharpCodePrivoder.CompileAssemblyFromFile(objCompilerParameters, inputFiles); + String outputMessage = ""; + foreach (var item in cr.Output) { + outputMessage += item + Environment.NewLine; + } + Console.WriteLine(outputMessage); + if (cr.Errors.HasErrors) { + Console.WriteLine("编译错误:"); + foreach (CompilerError err in cr.Errors) { + Console.WriteLine(err.ErrorText); + } + } + else { + Type[] types = cr.CompiledAssembly.GetTypes(); + + CodeCompileUnit compunit = new CodeCompileUnit(); + CodeNamespace ns = new CodeNamespace(types[0].Namespace); + compunit.Namespaces.Add(ns); + ns.Imports.Add(new CodeNamespaceImport("System")); + ns.Imports.Add(new CodeNamespaceImport("System.Reflection")); + ns.Imports.Add(new CodeNamespaceImport("Hprose.Common")); + foreach (Type t in types) { + if (t.IsInterface) { + ns.Types.Add(ImplementIt(t)); + } + } + StringBuilder fileContent = new StringBuilder(); + CodeGeneratorOptions options = new CodeGeneratorOptions(); + using (StringWriter sw = new StringWriter(fileContent)) { + objCSharpCodePrivoder.GenerateCodeFromNamespace(ns, sw, options); + } + File.WriteAllText(output, fileContent.ToString()); + + string[] files = new string[inputFiles.Length + 1]; + inputFiles.CopyTo(files, 0); + files[files.Length - 1] = output; + + objCompilerParameters.GenerateExecutable = false; + objCompilerParameters.GenerateInMemory = true; + objCompilerParameters.OutputAssembly = ""; + + cr = objCSharpCodePrivoder.CompileAssemblyFromFile(objCompilerParameters, files); + foreach (var item in cr.Output) { + outputMessage += item + Environment.NewLine; + } + Console.WriteLine(outputMessage); + if (cr.Errors.HasErrors) { + Console.WriteLine("编译错误:"); + foreach (CompilerError err in cr.Errors) { + Console.WriteLine(err.ErrorText); + } + } + } + + } + } +} diff --git a/hipig/hipig/Properties/AssemblyInfo.cs b/hipig/hipig/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..327fef5c --- /dev/null +++ b/hipig/hipig/Properties/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle ("hipig")] +[assembly: AssemblyDescription ("")] +[assembly: AssemblyConfiguration ("")] +[assembly: AssemblyCompany ("")] +[assembly: AssemblyProduct ("")] +[assembly: AssemblyCopyright ("andot")] +[assembly: AssemblyTrademark ("")] +[assembly: AssemblyCulture ("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion ("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/hipig/hipig/bin/Release/Hprose.Client.dll b/hipig/hipig/bin/Release/Hprose.Client.dll new file mode 100644 index 00000000..1b27db9c Binary files /dev/null and b/hipig/hipig/bin/Release/Hprose.Client.dll differ diff --git a/hipig/hipig/bin/Release/hipig.exe b/hipig/hipig/bin/Release/hipig.exe new file mode 100644 index 00000000..cc550199 Binary files /dev/null and b/hipig/hipig/bin/Release/hipig.exe differ diff --git a/hipig/hipig/hipig.csproj b/hipig/hipig/hipig.csproj new file mode 100644 index 00000000..820883c2 --- /dev/null +++ b/hipig/hipig/hipig.csproj @@ -0,0 +1,35 @@ + + + + Debug + AnyCPU + {EBDF43B1-5BB4-495B-AE69-7FF5D548D84D} + Exe + hipig + hipig + v4.5 + + + true + bin\Debug + 4 + true + + + true + bin\Release + 4 + true + + + + + Hprose.Client.dll + + + + + + + + \ No newline at end of file diff --git a/hipig/hipig/obj/Release/.NETFramework,Version=v4.5.AssemblyAttribute.cs b/hipig/hipig/obj/Release/.NETFramework,Version=v4.5.AssemblyAttribute.cs new file mode 100644 index 00000000..fdcb678c --- /dev/null +++ b/hipig/hipig/obj/Release/.NETFramework,Version=v4.5.AssemblyAttribute.cs @@ -0,0 +1,2 @@ +// +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.5", FrameworkDisplayName = "")] diff --git a/hipig/hipig/obj/Release/hipig.csproj.FilesWrittenAbsolute.txt b/hipig/hipig/obj/Release/hipig.csproj.FilesWrittenAbsolute.txt new file mode 100644 index 00000000..30631061 --- /dev/null +++ b/hipig/hipig/obj/Release/hipig.csproj.FilesWrittenAbsolute.txt @@ -0,0 +1,4 @@ +/Users/andot/Git/hprose-dotnet/hipig/hipig/obj/Release/.NETFramework,Version=v4.5.AssemblyAttribute.cs +/Users/andot/Git/hprose-dotnet/hipig/hipig/bin/Release/hipig.exe +/Users/andot/Git/hprose-dotnet/hipig/hipig/obj/Release/hipig.exe +/Users/andot/Git/hprose-dotnet/hipig/hipig/bin/Release/Hprose.Client.dll diff --git a/hipig/hipig/obj/Release/hipig.exe b/hipig/hipig/obj/Release/hipig.exe new file mode 100644 index 00000000..cc550199 Binary files /dev/null and b/hipig/hipig/obj/Release/hipig.exe differ