private static void DuplicateMethodSpecial(CsInterface interfaceType, CsMethod csMethod, CsTypeBase intPtrType) { bool hasComArrayLike = false; foreach(var csParameter in csMethod.Parameters) { if(csParameter.IsInComArrayLike) { hasComArrayLike = true; break; } } // Look for at least one parameter ComArray candidate if (hasComArrayLike) { // Create a new method and transforms all array of ComObject to ComArray<ComObject> var newMethod = (CsMethod)csMethod.Clone(); foreach (var csSubParameter in newMethod.Parameters) { if (csSubParameter.IsInComArrayLike) csSubParameter.PublicType = new CsComArray((CsInterface)csSubParameter.PublicType); } interfaceType.Add(newMethod); } if(hasComArrayLike || csMethod.RequestRawPtr) { // Create private method with raw pointers for arrays, with all arrays as pure IntPtr // In order to be able to generate method taking single element var rawMethod = (CsMethod)csMethod.Clone(); rawMethod.Visibility = Visibility.Private; foreach(var csSubParameter in rawMethod.Parameters) { if(csSubParameter.IsArray || csSubParameter.IsComObject || csSubParameter.HasPointer) { csSubParameter.PublicType = intPtrType; csSubParameter.IsArray = false; csSubParameter.Attribute = CsParameterAttribute.In; } } interfaceType.Add(rawMethod); } }
/// <summary> /// Processes the specified interface type. /// </summary> /// <param name="interfaceType">Type of the interface.</param> public void Process(CsInterface interfaceType ) { if (interfaceType.IsFullyMapped) return; // Set IsFullyMapped to avoid recursive mapping interfaceType.IsFullyMapped = true; // var cppInterface = interfaceType.CppElement as CppInterface; var cppInterface = (CppInterface)interfaceType.CppElement; // Associate Parent var parentType = Manager.FindBindType(cppInterface.ParentName); if (parentType != null) { interfaceType.Base = parentType; // Process base if it's not mapped already if (!parentType.IsFullyMapped) Process(parentType); } else { if (!interfaceType.IsCallback) interfaceType.Base = DefaultInterfaceCppObject; } // Warning, if Guid is null we need to recover it from a declared GUID if (string.IsNullOrEmpty(cppInterface.Guid)) { // Go up to the root base interface var rootBase = parentType; while (rootBase != null && rootBase is CsInterface && ((CsInterface)rootBase).Base != null) rootBase = ((CsInterface) rootBase).Base; // look for GUID only for ComObjects var cppGuid = cppInterface.ParentInclude.Find<CppGuid>("^IID_" + cppInterface.Name + "$").FirstOrDefault(); if (cppGuid == null) { // If Guid == null && BaseRoot != null && BaseRoot is a ComObject // then we probably missed a guid if (rootBase != null && rootBase.QualifiedName == Global.Name + ".ComObject") Logger.Warning("cannot find GUID"); } else interfaceType.Guid = cppGuid.Guid.ToString(); } // Handle Methods var generatedMethods = new List<CsMethod>(); var intPtrType = Manager.ImportType(typeof(IntPtr)); foreach (var cppMethod in cppInterface.Methods) { var cSharpMethod = (CsMethod)MethodTranform.Prepare(cppMethod); generatedMethods.Add(cSharpMethod); interfaceType.Add(cSharpMethod); MethodTranform.Process(cSharpMethod); // Add specialized method for ComArray DuplicateMethodSpecial(interfaceType, cSharpMethod, intPtrType); //MapMethod(cSharpMethod); //RegisterNativeInterop(cSharpMethod); // Allow overloads by changing the name to <name># string origCppName = cppInterface.Name + "::" + cppMethod.Name; string chosenCppName = origCppName; for (int i = 0; Manager.FindBindType(chosenCppName) != null; i++) chosenCppName = origCppName + i.ToString(); Manager.BindType(chosenCppName, cSharpMethod); } // Dispatch method to inner interface if any var mapInnerInterface = new Dictionary<string, CsInterface>(); // Make a copy of the methods var methods = interfaceType.Methods.ToList(); foreach (var csMethod in methods) { string cppName = interfaceType.CppElementName + "::" + csMethod.CppElement.Name; foreach (var keyValuePair in _mapMoveMethodToInnerInterface) { if (keyValuePair.Key.Match(cppName).Success) { string innerInterfaceName = keyValuePair.Value.InnerInterface; string parentInterfaceName = keyValuePair.Value.InheritedInterfaceName; CsInterface innerCsInterface; CsInterface parentCsInterface = null; if (parentInterfaceName != null) { if (!mapInnerInterface.TryGetValue(parentInterfaceName, out parentCsInterface)) { parentCsInterface = new CsInterface(null) { Name = parentInterfaceName }; mapInnerInterface.Add(parentInterfaceName, parentCsInterface); } } if (!mapInnerInterface.TryGetValue(innerInterfaceName, out innerCsInterface)) { // TODO custom cppInterface? innerCsInterface = new CsInterface(cppInterface) { Name = innerInterfaceName, PropertyAccesName = keyValuePair.Value.PropertyAccessName, Base = parentCsInterface ?? DefaultInterfaceCppObject }; // Add inner interface to root interface interfaceType.Add(innerCsInterface); interfaceType.Parent.Add(innerCsInterface); // Move method to inner interface mapInnerInterface.Add(innerInterfaceName, innerCsInterface); } interfaceType.Remove(csMethod); innerCsInterface.Add(csMethod); break; } } } // Remove dispatched methods from outer interface //foreach (var innerInterface in mapInnerInterface) //{ // foreach (var method in innerInterface.Value.Methods) // cppInterface.Remove(method.CppElement); //} // If interfaceType is DualCallback, then need to generate a default implem if (interfaceType.IsDualCallback) { var tagForInterface = cppInterface.GetTagOrDefault<MappingRule>(); var nativeCallback = new CsInterface(interfaceType.CppElement as CppInterface) { Name = interfaceType.Name + "Native", Visibility = Visibility.Internal }; // Update nativeCallback from tag if (tagForInterface != null) { if (tagForInterface.NativeCallbackVisibility.HasValue) nativeCallback.Visibility = tagForInterface.NativeCallbackVisibility.Value; if (tagForInterface.NativeCallbackName != null) nativeCallback.Name = tagForInterface.NativeCallbackName; } nativeCallback.Base = interfaceType.Base; if (nativeCallback.IsBaseComObject) { nativeCallback.Base = DefaultComObjectCallback; } // If Parent is a DualInterface, then inherit from Default Callback if (interfaceType.Base is CsInterface) { var parentInterface = interfaceType.Base as CsInterface; if (parentInterface.IsDualCallback) nativeCallback.Base = parentInterface.NativeImplem; } nativeCallback.IBase = interfaceType; interfaceType.NativeImplem = nativeCallback; foreach (var innerElement in interfaceType.Items) { if (innerElement is CsMethod) { var method = (CsMethod)innerElement; var newCsMethod = (CsMethod)method.Clone(); var tagForMethod = method.CppElement.GetTagOrDefault<MappingRule>(); bool keepMethodPublic = tagForMethod.IsKeepImplementPublic.HasValue && tagForMethod.IsKeepImplementPublic.Value; if (!keepMethodPublic) { newCsMethod.Visibility = Visibility.Internal; newCsMethod.Name = newCsMethod.Name + "_"; } nativeCallback.Add(newCsMethod); } else { Logger.Warning("Unhandled innerElement {0} for DualCallbackInterface {1}", innerElement, interfaceType.Name); } } nativeCallback.IsCallback = false; nativeCallback.IsDualCallback = true; interfaceType.Parent.Add(nativeCallback); } else { // If interface is a callback and parent is ComObject, then remove it var parentInterface = interfaceType.Base as CsInterface; if (parentInterface != null && parentInterface.IsDualCallback) { interfaceType.Base = parentInterface.NativeImplem; } else { // Refactor Properties CreateProperties(generatedMethods); } } // If interface is a callback and parent is ComObject, then remove it if (interfaceType.IsCallback ) { if (interfaceType.IsBaseComObject) interfaceType.Base = null; if (interfaceType.Base == null) interfaceType.Base = DefaultCallbackable; } }
private static void CreateMethodsForComArrayMethod(CsInterface interfaceType, CsMethod csMethod) { foreach (var csParameter in csMethod.Parameters) { // Look for at least one parameter ComArray candidate if (csParameter.IsInComArrayLike) { // Create a new method and transforms all array of ComObject to ComArray<ComObject> var newMethod = (CsMethod)csMethod.Clone(); foreach (var csSubParameter in newMethod.Parameters) { if (csSubParameter.IsInComArrayLike) csSubParameter.PublicType = new CsComArray((CsInterface)csSubParameter.PublicType); } interfaceType.Add(newMethod); break; } } }