Mercurial > hg > vboxdotnet
comparison InteropCodeGen/ComInteropProxyGenerator.cs @ 6:e640ca67b819
Added extended COM interop code generator for interfaces and proxies
author | Ivo Smits |
---|---|
date | Fri, 06 May 2011 04:02:43 +0200 |
parents | |
children | a7650e26195f |
comparison
equal
deleted
inserted
replaced
5:00fb4879d273 | 6:e640ca67b819 |
---|---|
1 using System; | |
2 using System.Collections.Generic; | |
3 using System.Text; | |
4 using System.IO; | |
5 | |
6 namespace VBoxSDK { | |
7 class ComInteropProxyGenerator { | |
8 public TextWriter Output { get; private set; } | |
9 public Boolean IncludeInheritedMembers { get; set; } | |
10 public String TypeModifiers { get; set; } | |
11 | |
12 public ComInteropProxyGenerator(TextWriter output) { | |
13 Output = output; | |
14 } | |
15 public void WriteLibrary(LibraryInfo lib) { | |
16 Output.WriteLine("interface IComProxy {"); | |
17 Output.WriteLine("IntPtr ComPointer { get; }"); | |
18 Output.WriteLine("void AddRef();"); | |
19 Output.WriteLine("}"); | |
20 foreach (KeyValuePair<String, InterfaceInfo> intf in lib.Interfaces) { | |
21 WriteInterface(intf.Value); | |
22 } | |
23 } | |
24 public void WriteInterface(InterfaceInfo intf) { | |
25 /*List<InterfaceMemberInfo> members = new List<InterfaceMemberInfo>(); | |
26 InterfaceInfo intfp = intf.Value; | |
27 while (intfp != null) { | |
28 members.AddRange(intfp.Members); | |
29 intfp = intfp.Extends; | |
30 }*/ | |
31 | |
32 foreach (InterfaceMemberInfo member in intf.Members) { | |
33 if (member is PropertyInfo) { | |
34 PropertyInfo memberi = (PropertyInfo)member; | |
35 if (memberi.Gettable) { | |
36 Output.Write("{2} delegate HRESULT {0}_{1}_get_Delegate(IntPtr pThis, ", intf.Name, memberi.Name, TypeModifiers); | |
37 if (memberi.Type is InterfaceTypeInfo) { | |
38 Output.WriteLine("out IntPtr value);"); | |
39 } else { | |
40 WriteTypeComMarshalAttributes(memberi.Type, null); | |
41 Output.WriteLine("out {0} value);", memberi.Type.Name); | |
42 } | |
43 } | |
44 if (memberi.Settable) { | |
45 Output.Write("{2} delegate HRESULT {0}_{1}_set_Delegate(IntPtr pThis, ", intf.Name, memberi.Name, TypeModifiers); | |
46 if (memberi.Type is InterfaceTypeInfo) { | |
47 Output.WriteLine("IntPtr value);"); | |
48 } else { | |
49 WriteTypeComMarshalAttributes(memberi.Type, null); | |
50 Output.WriteLine("{0} value);", memberi.Type.Name); | |
51 } | |
52 } | |
53 } else if (member is MethodInfo) { | |
54 MethodInfo memberi = (MethodInfo)member; | |
55 Output.Write("{0} delegate ", TypeModifiers); | |
56 Output.Write("HRESULT "); | |
57 Output.Write("{0}_{1}_Delegate(IntPtr mThis", intf.Name, memberi.Name); | |
58 foreach (MethodParameterInfo param in memberi.Parameters) { | |
59 Output.Write(", "); | |
60 if (param.Type is InterfaceTypeInfo) { | |
61 if (param.Output && !param.Input) Output.Write("out "); | |
62 else if (param.Reference) Output.Write("ref "); | |
63 Output.Write("IntPtr p{0}", param.Name); | |
64 } else { | |
65 WriteTypeComMarshalAttributes(param.Type, null); | |
66 if (param.Output && !param.Input) Output.Write("out "); | |
67 else if (param.Reference) Output.Write("ref "); | |
68 Output.Write("{0} p{1}", param.Type.Name, param.Name); | |
69 } | |
70 } | |
71 if (memberi.ReturnType != null) { | |
72 Output.Write(", "); | |
73 if (memberi.ReturnType is InterfaceTypeInfo) { | |
74 Output.Write("out IntPtr mOut"); | |
75 } else { | |
76 WriteTypeComMarshalAttributes(memberi.ReturnType, null); | |
77 Output.Write("out {0} mOut", memberi.ReturnType.Name); | |
78 } | |
79 } | |
80 Output.WriteLine(");"); | |
81 } | |
82 } | |
83 | |
84 Output.WriteLine("{1} struct {0}_vtable {{", intf.Name, TypeModifiers); | |
85 if (intf.Extends != null) { | |
86 Output.WriteLine("public {0}_vtable {0};", intf.Extends.Name); | |
87 } | |
88 foreach (InterfaceMemberInfo member in intf.Members) { | |
89 if (member is PropertyInfo) { | |
90 PropertyInfo memberi = (PropertyInfo)member; | |
91 if (memberi.Gettable) { | |
92 Output.WriteLine("[MarshalAs(UnmanagedType.FunctionPtr)] public {0}_{1}_get_Delegate get_{1};", intf.Name, memberi.Name); | |
93 } | |
94 if (memberi.Settable) { | |
95 Output.WriteLine("[MarshalAs(UnmanagedType.FunctionPtr)] public {0}_{1}_set_Delegate set_{1};", intf.Name, memberi.Name); | |
96 } | |
97 } else if (member is MethodInfo) { | |
98 MethodInfo memberi = (MethodInfo)member; | |
99 Output.WriteLine("[MarshalAs(UnmanagedType.FunctionPtr)] public {0}_{1}_Delegate {1};", intf.Name, memberi.Name); | |
100 } | |
101 } | |
102 Output.WriteLine("}"); | |
103 | |
104 Output.WriteLine("{1} unsafe class {0}_Proxy : IComProxy, {0} {{", intf.Name, TypeModifiers); | |
105 Output.WriteLine("public static Guid IID = new Guid(\"{0}\");", intf.IID); | |
106 Output.WriteLine("private IntPtr pointer;"); | |
107 Output.WriteLine("private {0}_vtable functions;", intf.Name); | |
108 Output.WriteLine("public {0}_Proxy(IntPtr p) {{", intf.Name); | |
109 Output.WriteLine("IUnknown_vtable ft = (IUnknown_vtable)Marshal.PtrToStructure(*(IntPtr*)p, typeof(IUnknown_vtable));"); | |
110 Output.WriteLine("Guid IIDCopy = IID;"); | |
111 Output.WriteLine("HRESULT hr = ft.QueryInterface(p, ref IIDCopy, out pointer);"); | |
112 Output.WriteLine("Marshal.ThrowExceptionForHR(hr);"); | |
113 //Output.WriteLine("ft.AddRef(p);"); | |
114 Output.WriteLine("functions = ({0}_vtable)Marshal.PtrToStructure(*(IntPtr*)pointer, typeof({0}_vtable));", intf.Name); | |
115 Output.WriteLine("}"); | |
116 Output.WriteLine("IntPtr IComProxy.ComPointer { get { return pointer; } }"); | |
117 Output.Write("~{0}_Proxy() {{ functions", intf.Name); | |
118 { | |
119 InterfaceInfo intfp = intf; | |
120 while (intfp.Extends != null && intfp.Name != "IUnknown") { | |
121 intfp = intfp.Extends; | |
122 Output.Write(".{0}", intfp.Name); | |
123 } | |
124 } | |
125 Output.WriteLine(".Release(pointer); }"); | |
126 WriteInterfaceMembers(intf, ""); | |
127 Output.WriteLine("}"); | |
128 } | |
129 private void WriteInterfaceMembers(InterfaceInfo intf, String ftprefix) { | |
130 if (intf.Extends != null) WriteInterfaceMembers(intf.Extends, ftprefix + "." + intf.Extends.Name); | |
131 WriteInterfaceMembers(intf.Members, ftprefix); | |
132 } | |
133 private void WriteInterfaceMembers(ICollection<InterfaceMemberInfo> members, String ftprefix) { | |
134 foreach (InterfaceMemberInfo member in members) { | |
135 if (member is PropertyInfo) { | |
136 PropertyInfo memberi = (PropertyInfo)member; | |
137 if (!memberi.Gettable && !memberi.Settable) continue; | |
138 Output.WriteLine("public {0} {1} {{", memberi.Type.Name, memberi.Name); | |
139 if (memberi.Gettable) { | |
140 Output.WriteLine("get {"); | |
141 if (memberi.Type is InterfaceTypeInfo) { | |
142 Output.WriteLine("IntPtr value;"); | |
143 } else { | |
144 Output.WriteLine("{0} value;", memberi.Type.Name); | |
145 } | |
146 Output.WriteLine("HRESULT hr = functions{1}.get_{0}(pointer, out value);", memberi.Name, ftprefix); | |
147 Output.WriteLine("Marshal.ThrowExceptionForHR(hr);"); | |
148 if (memberi.Type is InterfaceTypeInfo) { | |
149 Output.WriteLine("return value == IntPtr.Zero ? null : new {0}_Proxy(value);", memberi.Type.Name); | |
150 } else { | |
151 Output.WriteLine("return value;"); | |
152 } | |
153 Output.WriteLine("}"); | |
154 } | |
155 if (memberi.Settable) { | |
156 Output.WriteLine("set {"); | |
157 if (memberi.Type is InterfaceTypeInfo) { | |
158 Output.WriteLine("IntPtr pvalue;"); | |
159 Output.WriteLine("if (pvalue == null) {"); | |
160 Output.WriteLine("pvalue = IntPtr.Zero;"); | |
161 Output.WriteLine("} else if (pvalue is IComProxy) {"); | |
162 Output.WriteLine("((IComProxy)value).AddRef();"); | |
163 Output.WriteLine("pvalue = ((IComProxy)value).ComPointer;"); | |
164 Output.WriteLine("} else {"); | |
165 Output.WriteLine("pvalue = Marshal.GetIUnknownForObject(value);"); | |
166 Output.WriteLine("}"); | |
167 Output.WriteLine("HRESULT hr = functions{1}.set_{0}(pointer, pvalue);", memberi.Name, ftprefix); | |
168 } else { | |
169 Output.WriteLine("HRESULT hr = functions{1}.set_{0}(pointer, value);", memberi.Name, ftprefix); | |
170 } | |
171 Output.WriteLine("Marshal.ThrowExceptionForHR(hr);"); | |
172 Output.WriteLine("}"); | |
173 } | |
174 Output.WriteLine("}"); | |
175 } else if (member is MethodInfo) { | |
176 MethodInfo memberi = (MethodInfo)member; | |
177 Output.Write("public "); | |
178 if (memberi.ReturnType == null) { | |
179 Output.Write("void"); | |
180 } else { | |
181 Output.Write(memberi.ReturnType.Name); | |
182 } | |
183 Output.Write(" {0}(", memberi.Name); | |
184 Boolean first = true; | |
185 foreach (MethodParameterInfo parameter in memberi.Parameters) { | |
186 if (first) { | |
187 first = false; | |
188 } else { | |
189 Output.Write(", "); | |
190 } | |
191 if (parameter.Output && !parameter.Input) { | |
192 Output.Write("out "); | |
193 } else if (parameter.Reference) { | |
194 Output.Write("ref "); | |
195 } | |
196 Output.Write("{0} p{1}", parameter.Type.Name, parameter.Name); | |
197 } | |
198 Output.WriteLine(") {"); | |
199 if (memberi.ReturnType != null) { | |
200 if (memberi.ReturnType is InterfaceTypeInfo) { | |
201 Output.WriteLine("IntPtr retval;"); | |
202 } else { | |
203 Output.WriteLine("{0} retval;", memberi.ReturnType.Name); | |
204 } | |
205 } | |
206 foreach (MethodParameterInfo parameter in memberi.Parameters) { | |
207 if (parameter.Type is InterfaceTypeInfo) { | |
208 Output.WriteLine("IntPtr lp{0};", parameter.Name); | |
209 if (parameter.Input) { | |
210 Output.WriteLine("if (p{0} == null) {{", parameter.Name); | |
211 Output.WriteLine("lp{0} = IntPtr.Zero;", parameter.Name); | |
212 Output.WriteLine("}} else if (p{0} is IComProxy) {{", parameter.Name); | |
213 Output.WriteLine("((IComProxy)p{0}).AddRef();", parameter.Name); | |
214 Output.WriteLine("lp{0} = ((IComProxy)p{0}).ComPointer;", parameter.Name); | |
215 Output.WriteLine("} else {"); | |
216 Output.WriteLine("lp{0} = Marshal.GetIUnknownForObject(p{0});", parameter.Name); | |
217 Output.WriteLine("}"); | |
218 } | |
219 } | |
220 } | |
221 | |
222 Output.Write("HRESULT hr = functions{1}.{0}(pointer", memberi.Name, ftprefix); | |
223 foreach (MethodParameterInfo parameter in memberi.Parameters) { | |
224 Output.Write(", "); | |
225 if (parameter.Output && !parameter.Input) { | |
226 Output.Write("out "); | |
227 } else if (parameter.Reference) { | |
228 Output.Write("ref "); | |
229 } | |
230 if (parameter.Type is InterfaceTypeInfo) { | |
231 Output.Write("lp{0}", parameter.Name); | |
232 } else { | |
233 Output.Write("p{0}", parameter.Name); | |
234 } | |
235 } | |
236 if (memberi.ReturnType != null) Output.Write(", out retval"); | |
237 Output.WriteLine(");"); | |
238 Output.WriteLine("Marshal.ThrowExceptionForHR(hr);"); | |
239 | |
240 foreach (MethodParameterInfo parameter in memberi.Parameters) { | |
241 if (parameter.Type is InterfaceTypeInfo) { | |
242 if (parameter.Output) { | |
243 Output.WriteLine("p{0} = lp{0} == IntPtr.Zero ? null : new {1}_Proxy(lp{0});", parameter.Name, parameter.Type.Name); | |
244 } | |
245 } | |
246 } | |
247 | |
248 if (memberi.ReturnType != null) { | |
249 if (memberi.ReturnType is InterfaceTypeInfo) { | |
250 Output.WriteLine("return retval == IntPtr.Zero ? null : new {0}_Proxy(retval);", memberi.ReturnType.Name); | |
251 } else { | |
252 Output.WriteLine("return retval;"); | |
253 } | |
254 } | |
255 Output.WriteLine("}"); | |
256 } | |
257 } | |
258 } | |
259 public void WriteTypeComMarshalAttributes(TypeInfo type, String paramType) { | |
260 if (type == null) return; | |
261 String MarshalAs = null; | |
262 if (type is InterfaceTypeInfo) { | |
263 MarshalAs = "Interface"; | |
264 } else if (type is StringTypeInfo) { | |
265 MarshalAs = (type as StringTypeInfo).UnmanagedType.ToString(); | |
266 } | |
267 if (MarshalAs != null) { | |
268 Output.Write("["); | |
269 if (paramType != null) Output.Write("{0}: ", paramType); | |
270 Output.Write("MarshalAs(UnmanagedType.{0})] ", MarshalAs); | |
271 } | |
272 } | |
273 } | |
274 } |