Browse Source

Started rough beginnings of QtBindings. Fixes to make this possible: support static C++ class methods, support managed wrapper inheritance to parallel C++ classes, added Base<> marker interface; will help support multiple inheritance, and more. Added small QtTest of QtBindings... currently crashes and burns.

git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@48 a470b8cb-0e6f-1642-1b45-71e107334c4b
pull/1/head
alexander.corrado 15 years ago
parent
commit
16b1a614f2
  1. 12
      CPPInterop.sln
  2. 51
      CPPTestLib/CSimpleClass.cpp
  3. 111
      Mono.VisualC.Interop/ABI/CppAbi.cs
  4. 35
      Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs
  5. 1
      Mono.VisualC.Interop/ABI/VTable.cs
  6. 31
      Mono.VisualC.Interop/Attributes.cs
  7. 10
      Mono.VisualC.Interop/CppInstancePtr.cs
  8. 49
      Mono.VisualC.Interop/CppObjectMarshaler.cs
  9. 7
      Mono.VisualC.Interop/Interfaces.cs
  10. 1
      Mono.VisualC.Interop/Mono.VisualC.Interop.csproj
  11. 27
      QtBindings/AssemblyInfo.cs
  12. 83
      QtBindings/Core/QCoreApplication.cs
  13. 10
      QtBindings/Core/QGlobal.cs
  14. 61
      QtBindings/Core/QObject.cs
  15. 56
      QtBindings/Gui/QApplication.cs
  16. 25
      QtBindings/Libs.cs
  17. 63
      QtBindings/QtBindings.csproj
  18. 4
      QtBindings/QtBindings.dll.config
  19. 27
      QtTest/AssemblyInfo.cs
  20. 16
      QtTest/Main.cs
  21. 50
      QtTest/QtTest.csproj
  22. 4
      Tests/Support/CSimpleClass.cs
  23. 6
      Tests/Support/CppMockObject.cs

12
CPPInterop.sln

@ -7,6 +7,10 @@ Project("{2857B73E-F847-4B02-9238-064979017E93}") = "CPPTestLib", "CPPTestLib\CP @@ -7,6 +7,10 @@ Project("{2857B73E-F847-4B02-9238-064979017E93}") = "CPPTestLib", "CPPTestLib\CP
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{3C290CBE-CA39-47F6-B3A0-ACD16C5A38C8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtTest", "QtTest\QtTest.csproj", "{3EE6B50E-58FB-4391-AF01-3FCB1A29B0D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QtBindings", "QtBindings\QtBindings.csproj", "{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -17,10 +21,18 @@ Global @@ -17,10 +21,18 @@ Global
{3C290CBE-CA39-47F6-B3A0-ACD16C5A38C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C290CBE-CA39-47F6-B3A0-ACD16C5A38C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C290CBE-CA39-47F6-B3A0-ACD16C5A38C8}.Release|Any CPU.Build.0 = Release|Any CPU
{3EE6B50E-58FB-4391-AF01-3FCB1A29B0D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3EE6B50E-58FB-4391-AF01-3FCB1A29B0D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EE6B50E-58FB-4391-AF01-3FCB1A29B0D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EE6B50E-58FB-4391-AF01-3FCB1A29B0D7}.Release|Any CPU.Build.0 = Release|Any CPU
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Release|Any CPU.Build.0 = Release|Any CPU
{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}.Release|Any CPU.Build.0 = Release|Any CPU
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Release|Any CPU.ActiveCfg = Release|Any CPU

51
CPPTestLib/CSimpleClass.cpp

@ -24,32 +24,19 @@ public: @@ -24,32 +24,19 @@ public:
printf ("~CSimpleClass\n");
}
void M0 ()
{
printf ("C++/CSimpleClass::M0()\n");
V0 (value, value + 1);
V1 (value);
}
void M0 ();
void M1 (int x);
void M2 (int x, int y);
virtual void V0 (int x, int y)
{
printf ("C++/CSimpleClass::V0(%d, %d)\n", x, y);
}
void M1 (int x)
{
printf ("C++/CSimpleClass::M1(%d)\n", x);
}
virtual void V1(int x)
{
printf("C++/CSimpleClass::V1(%d)\n", x);
}
void M2(int x, int y)
{
printf ("C++/CSimpleClass::M2(%d, %d)\n", x, y);
}
};
class EXPORT CSimpleSubClass : CSimpleClass {
@ -68,8 +55,38 @@ public: @@ -68,8 +55,38 @@ public:
{
printf("C++/CSimpleSubClass::V1(%d)\n", x);
}
virtual void V2 ()
{
printf("C++/CSimpleSubClass::V2() - value: %d\n", this->value);
}
void M3 ();
};
void CSimpleClass::M0 ()
{
printf ("C++/CSimpleClass::M0()\n");
V0 (value, value + 1);
V1 (value);
}
void CSimpleClass::M1 (int x)
{
printf ("C++/CSimpleClass::M1(%d)\n", x);
}
void CSimpleClass::M2(int x, int y)
{
printf ("C++/CSimpleClass::M2(%d, %d)\n", x, y);
}
void CSimpleSubClass::M3 ()
{
printf("C++/CSimpleSubClass::M3()\n");
this->M0 ();
}
extern "C" {
CSimpleSubClass* CreateCSimpleSubClass (int value)
{

111
Mono.VisualC.Interop/ABI/CppAbi.cs

@ -28,7 +28,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -28,7 +28,7 @@ namespace Mono.VisualC.Interop.ABI {
protected string library, class_name;
protected VTable vtable;
protected FieldBuilder vtable_field;
protected FieldBuilder vtable_field, native_size_field;
protected ILGenerator ctor_il;
// default settings that subclasses can override:
@ -58,31 +58,45 @@ namespace Mono.VisualC.Interop.ABI { @@ -58,31 +58,45 @@ namespace Mono.VisualC.Interop.ABI {
var properties = ( // get all properties defined on the interface
from property in interface_type.GetProperties ()
select property
).Union( // ... as well as those defined on inherited interfaces
).Union ( // ... as well as those defined on inherited interfaces
from iface in interface_type.GetInterfaces ()
from property in iface.GetProperties ()
select property
);
var methods = ( // get all methods defined on the interface
from method in interface_type.GetMethods ()
orderby method.MetadataToken
select method
).Union( // ... as well as those defined on inherited interfaces
var methods = ( // get all methods defined on inherited interfaces first
from iface in interface_type.GetInterfaces ()
from method in iface.GetMethods ()
select method
).Union ( // ... as well as those defined on this interface
from method in interface_type.GetMethods ()
orderby method.MetadataToken
select method
);
var managedOverrides = from method in methods
where Modifiers.IsVirtual (method)
orderby method.MetadataToken
select GetManagedOverrideTrampoline (method, vtable_override_filter);
// TODO: If a method in a base class interface is defined again in a child class
// interface with exactly the same signature, it will prolly share a vtable slot
// first, pull in all virtual methods from base classes
var baseVirtualMethods = from iface in interface_type.GetInterfaces ()
where iface.Name.Equals ("Base`1")
from method in iface.GetGenericArguments ().First ().GetMethods ()
where Modifiers.IsVirtual (method)
orderby method.MetadataToken
select GetManagedOverrideTrampoline (method, vtable_override_filter);
vtable = make_vtable_method (managedOverrides.ToArray ());
var virtualMethods = baseVirtualMethods.Concat ( // now create managed overrides for virtuals in this class
from method in methods
where Modifiers.IsVirtual (method)
orderby method.MetadataToken
select GetManagedOverrideTrampoline (method, vtable_override_filter)
);
vtable = make_vtable_method (virtualMethods.ToArray ());
int vtableIndex = baseVirtualMethods.Count ();
// Implement all methods
int vtableIndex = 0;
foreach (var method in methods) {
// Skip over special methods like property accessors -- properties will be handled later
if (method.IsSpecialName)
@ -99,7 +113,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -99,7 +113,7 @@ namespace Mono.VisualC.Interop.ABI {
DefineProperty (property);
ctor_il.Emit (OpCodes.Ret);
return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable);
return (Iface)Activator.CreateInstance (impl_type.CreateType (), vtable, NativeSize);
}
// These methods might be more commonly overridden for a given C++ ABI:
@ -141,8 +155,10 @@ namespace Mono.VisualC.Interop.ABI { @@ -141,8 +155,10 @@ namespace Mono.VisualC.Interop.ABI {
impl_type.AddInterfaceImplementation (interface_type);
vtable_field = impl_type.DefineField ("_vtable", typeof (VTable), FieldAttributes.InitOnly | FieldAttributes.Private);
native_size_field = impl_type.DefineField ("_nativeSize", typeof (int), FieldAttributes.InitOnly | FieldAttributes.Private);
ConstructorBuilder ctor = impl_type.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
new Type[] { typeof (VTable) });
new Type[] { typeof (VTable), typeof (int) });
ctor_il = ctor.GetILGenerator ();
@ -150,6 +166,10 @@ namespace Mono.VisualC.Interop.ABI { @@ -150,6 +166,10 @@ namespace Mono.VisualC.Interop.ABI {
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_1);
ctor_il.Emit (OpCodes.Stfld, vtable_field);
// this._nativeSize = (native size passed to constructor)
ctor_il.Emit (OpCodes.Ldarg_0);
ctor_il.Emit (OpCodes.Ldarg_2);
ctor_il.Emit (OpCodes.Stfld, native_size_field);
}
protected virtual MethodBuilder DefineMethod (MethodInfo interfaceMethod, int index)
@ -171,17 +191,28 @@ namespace Mono.VisualC.Interop.ABI { @@ -171,17 +191,28 @@ namespace Mono.VisualC.Interop.ABI {
il.Emit (OpCodes.Ret);
return trampoline;
} else if (methodType == MethodType.ManagedAlloc) {
EmitManagedAlloc (il);
EmitManagedAlloc (il, interfaceMethod);
il.Emit (OpCodes.Ret);
return trampoline;
}
// 2. Load the native C++ instance pointer
LocalBuilder cppInstancePtr, nativePtr;
EmitLoadInstancePtr (il, parameterTypes[0], out cppInstancePtr, out nativePtr);
bool isStatic = true;
LocalBuilder cppInstancePtr = null;
LocalBuilder nativePtr = null;
// If we're not a static method, do the following ...
if (!Modifiers.IsStatic (interfaceMethod))
{
isStatic = false;
if (parameterTypes.Length < 1)
throw new ArgumentException ("First argument to non-static C++ method must be IntPtr or CppInstancePtr.");
// 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException
EmitCheckDisposed (il, nativePtr, methodType);
// 2. Load the native C++ instance pointer
EmitLoadInstancePtr (il, parameterTypes[0], out cppInstancePtr, out nativePtr);
// 3. Make sure our native pointer is a valid reference. If not, throw ObjectDisposedException
EmitCheckDisposed (il, nativePtr, methodType);
}
MethodInfo nativeMethod;
if (Modifiers.IsVirtual (interfaceMethod))
@ -199,7 +230,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -199,7 +230,7 @@ namespace Mono.VisualC.Interop.ABI {
break;
default: // regular native method
EmitCallNative (il, nativeMethod, parameterTypes.Length, nativePtr);
EmitCallNative (il, nativeMethod, isStatic, parameterTypes.Length, nativePtr);
break;
}
@ -219,7 +250,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -219,7 +250,7 @@ namespace Mono.VisualC.Interop.ABI {
Type retType = imethod.ReturnType;
FieldBuilder fieldData;
// C++ interface properties are either to return the VTable or to access C++ fields
// C++ interface properties are either to return the VTable, get NativeSize, or to access C++ fields
if (retType.IsGenericType && retType.GetGenericTypeDefinition ().Equals (typeof (CppField<>))) {
// define a new field for the property
fieldData = impl_type.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private);
@ -242,6 +273,8 @@ namespace Mono.VisualC.Interop.ABI { @@ -242,6 +273,8 @@ namespace Mono.VisualC.Interop.ABI {
ctor_il.Emit (OpCodes.Stfld, fieldData);
} else if (retType.Equals (typeof (VTable)))
fieldData = vtable_field;
else if (retType.Equals (typeof (int)))
fieldData = native_size_field;
else
throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField.");
@ -360,11 +393,18 @@ namespace Mono.VisualC.Interop.ABI { @@ -360,11 +393,18 @@ namespace Mono.VisualC.Interop.ABI {
* Emits IL to allocate the memory for a new instance of the C++ class.
* To complete method, emit OpCodes.Ret.
*/
protected virtual void EmitManagedAlloc (ILGenerator il)
protected virtual void EmitManagedAlloc (ILGenerator il, MethodInfo interfaceMethod)
{
//TODO: Do not hard-emit native size in case assembly is saved?
il.Emit (OpCodes.Ldc_I4, NativeSize);
Type paramType = interfaceMethod.GetParameters () [0].ParameterType;
if (typeof (ICppObject).IsAssignableFrom (paramType))
{
// TODO: This is probably going to be causing us to alloc too much memory
// if the ICppObject is returning impl.NativeSize + base.NativeSize. (We get FieldOffsetPadding
// each time).
il.Emit (OpCodes.Ldarg_1);
il.Emit (OpCodes.Callvirt, typeof (ICppObject).GetProperty ("NativeSize").GetGetMethod ());
} else
il.Emit (OpCodes.Ldfld, native_size_field);
if (wrapper_type != null) {
// load managed object
@ -381,7 +421,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -381,7 +421,7 @@ namespace Mono.VisualC.Interop.ABI {
protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, int parameterCount,
LocalBuilder nativePtr)
{
EmitCallNative (il, nativeMethod, parameterCount, nativePtr);
EmitCallNative (il, nativeMethod, false, parameterCount, nativePtr);
EmitInitVTable (il, nativePtr);
}
@ -398,7 +438,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -398,7 +438,7 @@ namespace Mono.VisualC.Interop.ABI {
il.Emit (OpCodes.Brfalse_S, bail);
EmitResetVTable (il, nativePtr);
EmitCallNative (il, nativeMethod, parameterCount, nativePtr);
EmitCallNative (il, nativeMethod, false, parameterCount, nativePtr);
il.MarkLabel (bail);
}
@ -408,11 +448,16 @@ namespace Mono.VisualC.Interop.ABI { @@ -408,11 +448,16 @@ namespace Mono.VisualC.Interop.ABI {
* GetPInvokeForMethod or the MethodInfo of a vtable method.
* To complete method, emit OpCodes.Ret.
*/
protected virtual void EmitCallNative (ILGenerator il, MethodInfo nativeMethod, int parameterCount,
protected virtual void EmitCallNative (ILGenerator il, MethodInfo nativeMethod, bool isStatic, int parameterCount,
LocalBuilder nativePtr)
{
il.Emit (OpCodes.Ldloc_S, nativePtr);
for (int i = 2; i <= parameterCount; i++)
int argLoadStart = 1; // For static methods, just strip off arg0 (.net this pointer)
if (!isStatic)
{
argLoadStart = 2; // For instance methods, strip off CppInstancePtr and pass the corresponding IntPtr
il.Emit (OpCodes.Ldloc_S, nativePtr);
}
for (int i = argLoadStart; i <= parameterCount; i++)
il.Emit (OpCodes.Ldarg, i);
il.Emit (OpCodes.Call, nativeMethod);
@ -500,7 +545,7 @@ namespace Mono.VisualC.Interop.ABI { @@ -500,7 +545,7 @@ namespace Mono.VisualC.Interop.ABI {
} else if (firstParamType.Equals (typeof (IntPtr)))
il.Emit (OpCodes.Stloc_S, native);
else
throw new ArgumentException ("First argument to C++ method must be IntPtr or CppInstancePtr.");
throw new ArgumentException ("First argument to non-static C++ method must be IntPtr or CppInstancePtr.");
}
protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip)

35
Mono.VisualC.Interop/ABI/Impl/ItaniumAbi.cs

@ -52,18 +52,41 @@ namespace Mono.VisualC.Interop.ABI { @@ -52,18 +52,41 @@ namespace Mono.VisualC.Interop.ABI {
nm.Append("E");
if (parameters.Length == 1) { //only the C++ "this" object
int argStart = (Modifiers.IsStatic (methodInfo)? 0 : 1);
if (parameters.Length == argStart) { // no args (other than C++ "this" object)
nm.Append("v");
} else for (int i = 1; i < parameters.Length; i++) {
nm.Append(GetTypeCode(parameters[i].ParameterType));
} else for (int i = argStart; i < parameters.Length; i++) {
nm.Append(GetTypeCode(parameters[i]));
}
return nm.ToString();
}
protected virtual string GetTypeCode(Type t) {
if (t.Equals(typeof(int))) return "i";
throw new NotSupportedException("Unsupported parameter type: " + t.ToString());
protected virtual string GetTypeCode(ParameterInfo param) {
Type type = Modifiers.GetMangleType (param);
Type element = type;
StringBuilder code = new StringBuilder ();
if (type.IsByRef)
{
code.Append ("R");
element = type.GetElementType ();
}
if (type.IsArray)
{
code.Append ("P");
element = type.GetElementType ();
}
if (element.Equals (typeof (int))) code.Append ("i");
else if (element.Equals (typeof (string))) code.Append ("Pc"); // char *
else if (typeof (ICppObject).IsAssignableFrom (element)) { code.Append(element.Name.Length); code.Append(element.Name); }
else throw new NotSupportedException ("Unsupported parameter type: " + type.ToString ());
return code.ToString ();
}
}

1
Mono.VisualC.Interop/ABI/VTable.cs

@ -17,6 +17,7 @@ using System.Runtime.InteropServices; @@ -17,6 +17,7 @@ using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop.ABI {
public delegate VTable MakeVTableDelegate (Delegate[] overrides);
// TODO: RTTI
public abstract class VTable : IDisposable {
// The COM-interop-based implemenation is the default because it offers better

31
Mono.VisualC.Interop/Attributes.cs

@ -8,20 +8,51 @@ @@ -8,20 +8,51 @@
//
using System;
using System.Linq;
using System.Reflection;
namespace Mono.VisualC.Interop {
[AttributeUsage (AttributeTargets.Method)]
public class VirtualAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class StaticAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Method)]
public class OverrideNativeAttribute : Attribute {}
[AttributeUsage (AttributeTargets.Parameter)]
public class MangleAsAttribute : Attribute {
public Type MangleType { get; private set; }
public MangleAsAttribute (Type mangleType)
{
this.MangleType = mangleType;
}
public MangleAsAttribute (string mangleTypeAsString)
{
this.MangleType = Type.GetType (mangleTypeAsString);
}
}
public static class Modifiers {
public static bool IsVirtual (MethodInfo method)
{
return method.IsDefined (typeof (VirtualAttribute), false);
}
public static bool IsStatic (MethodInfo method)
{
return method.IsDefined (typeof (StaticAttribute), false);
}
public static Type GetMangleType (ParameterInfo param)
{
MangleAsAttribute maa = (MangleAsAttribute)param.GetCustomAttributes (typeof (MangleAsAttribute), false).FirstOrDefault ();
if (maa == null)
return param.ParameterType;
return maa.MangleType;
}
}
}

10
Mono.VisualC.Interop/CppInstancePtr.cs

@ -75,8 +75,8 @@ namespace Mono.VisualC.Interop { @@ -75,8 +75,8 @@ namespace Mono.VisualC.Interop {
// Get a CppInstancePtr for an existing C++ instance from an IntPtr
public CppInstancePtr (IntPtr native)
{
if (native == IntPtr.Zero)
throw new ArgumentOutOfRangeException ("native cannot be null pointer");
//if (native == IntPtr.Zero)
// throw new ArgumentOutOfRangeException ("native cannot be null pointer");
ptr = native;
manage_memory = false;
@ -103,6 +103,12 @@ namespace Mono.VisualC.Interop { @@ -103,6 +103,12 @@ namespace Mono.VisualC.Interop {
}
}
public int NativeSize {
get {
throw new NotImplementedException ();
}
}
public bool IsManagedAlloc {
get { return manage_memory; }
}

49
Mono.VisualC.Interop/CppObjectMarshaler.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
using System;
using System.Runtime.InteropServices;
namespace Mono.VisualC.Interop {
public class CppObjectMarshaler : ICustomMarshaler {
private static CppObjectMarshaler marshaler = null;
private CppObjectMarshaler () {
}
public IntPtr MarshalManagedToNative (object managedObj)
{
if (managedObj == null)
return IntPtr.Zero;
ICppObject cppObject = managedObj as ICppObject;
if (cppObject == null)
throw new ArgumentException ("Object to marshal must implement ICppObject");
return cppObject.Native;
}
public object MarshalNativeToManaged (IntPtr pNativeData)
{
throw new NotImplementedException ();
}
public void CleanUpManagedData (object ManagedObj)
{
}
public void CleanUpNativeData (IntPtr pNativeData)
{
}
public int GetNativeDataSize ()
{
return -1;
}
public static ICustomMarshaler GetInstance(string cookie)
{
if(marshaler == null)
marshaler = new CppObjectMarshaler ();
return marshaler;
}
}
}

7
Mono.VisualC.Interop/Interfaces.cs

@ -13,10 +13,17 @@ using Mono.VisualC.Interop.ABI; @@ -13,10 +13,17 @@ using Mono.VisualC.Interop.ABI;
namespace Mono.VisualC.Interop {
public interface ICppObject : IDisposable {
IntPtr Native { get; }
int NativeSize { get; }
}
// A marker interface to signify that the vtable needs to include all
// methods inherited from T as well.
public interface Base<T> where T : ICppClass {
}
public interface ICppClass {
VTable ClassVTable { get; }
int NativeSize { get; }
}
// This should go without saying, but the C++ class must have a constructor

1
Mono.VisualC.Interop/Mono.VisualC.Interop.csproj

@ -49,6 +49,7 @@ @@ -49,6 +49,7 @@
<Compile Include="ABI\Impl\ItaniumAbi.cs" />
<Compile Include="ABI\Impl\VirtualOnlyAbi.cs" />
<Compile Include="ABI\Impl\MsvcAbi.cs" />
<Compile Include="CppObjectMarshaler.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>

27
QtBindings/AssemblyInfo.cs

@ -0,0 +1,27 @@ @@ -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("QtBindings")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[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("")]

83
QtBindings/Core/QCoreApplication.cs

@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
using System;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop;
namespace Qt.Core {
public class QCoreApplication : QObject {
#region Sync with qcoreapplication.h
// C++ interface
protected interface IQCoreApplication : ICppClassOverridable<QCoreApplication>, Base<QObject.IQObject> {
void QCoreApplication (CppInstancePtr @this, [MangleAs ("System.Int32&")] IntPtr argc,
[MangleAs (typeof (string[]))] IntPtr argv);
// ...
[Static] int exec ();
// ...
[Virtual] bool notify (CppInstancePtr @this, IntPtr qObject, IntPtr qEvent);
[Virtual] bool compressEvent (CppInstancePtr @this, IntPtr qEvent, IntPtr qObject, IntPtr qPostEventList);
}
// C++ fields
private struct _QCoreApplication {
}
#endregion
private static IQCoreApplication impl = Qt.Libs.QtCore.GetClass<IQCoreApplication,_QCoreApplication,QCoreApplication> ("QCoreApplication");
protected IntPtr argc;
protected IntPtr argv;
public QCoreApplication () : this (true)
{
this.native = impl.Alloc (this);
impl.QCoreApplication (native, argc, argv);
}
protected QCoreApplication (bool foo) : base (IntPtr.Zero)
{
// for some reason, this includes arg0, but the args passed to Main (string[]) do not!
string[] args = Environment.GetCommandLineArgs ();
int argCount = args.Length;
argc = Marshal.AllocHGlobal (sizeof (int));
Marshal.WriteInt32 (argc, argCount);
argv = Marshal.AllocHGlobal (Marshal.SizeOf (typeof (IntPtr)) * argCount);
for (var i = 0; i < argCount; i++) {
IntPtr arg = Marshal.StringToHGlobalAnsi (args [i]);
Marshal.WriteIntPtr (argv, i * Marshal.SizeOf (typeof (IntPtr)), arg);
}
}
public QCoreApplication (IntPtr native) : base (native)
{
}
// TODO: Should this be virtual in C#? was static in C++, but alas,
// I made it an instance, since that seems to fit .net semantics a bit better...
// but if I don't make it virtual, then what to do about Exec () in QApplication?
public virtual int Exec ()
{
return impl.exec ();
}
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize; }
}
public override void Dispose ()
{
impl.Destruct (native);
FreeArgcAndArgv ();
native.Dispose ();
}
protected void FreeArgcAndArgv ()
{
Marshal.FreeHGlobal (argc);
for (var i = 0; i < Environment.GetCommandLineArgs ().Length; i++)
Marshal.FreeHGlobal (Marshal.ReadIntPtr (argv, i * Marshal.SizeOf (typeof (IntPtr))));
Marshal.FreeHGlobal (argv);
}
}
}

10
QtBindings/Core/QGlobal.cs

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
using System;
namespace Qt.Core {
public static class QGlobal {
public const string QT_VERSION_STR = "4.6.2";
public const int QT_VERSION = 0x040602;
}
}

61
QtBindings/Core/QObject.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
using System;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop;
namespace Qt.Core {
public class QObject : ICppObject {
#region Sync with qobject.h
// C++ interface
protected interface IQObject : ICppClassOverridable<QObject> {
void QObject (CppInstancePtr @this, [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof (CppObjectMarshaler))] QObject parent);
[Virtual] bool @event (CppInstancePtr @this, IntPtr qEvent);
[Virtual] bool eventFilter (CppInstancePtr @this, IntPtr qObject, IntPtr qEvent);
[Virtual] void timerEvent (CppInstancePtr @this, IntPtr qTimerEvent);
[Virtual] void childEvent (CppInstancePtr @this, IntPtr qChildEvent);
[Virtual] void customEvent (CppInstancePtr @this, IntPtr qEvent);
[Virtual] void connectNotify (CppInstancePtr @this, string signal);
[Virtual] void disconnectNotify (CppInstancePtr @this, string signal);
}
// C++ fields
private struct _QObject {
public IntPtr d_ptr;
}
#endregion
private static IQObject impl = Qt.Libs.QtCore.GetClass<IQObject,_QObject,QObject> ("QObject");
protected CppInstancePtr native;
public QObject ()
{
native = impl.Alloc (this);
impl.QObject (native, null);
}
public QObject (QObject parent)
{
native = impl.Alloc (this);
impl.QObject (native, parent);
}
public QObject (IntPtr native)
{
this.native = native;
}
public IntPtr Native {
get { return (IntPtr)native; }
}
public virtual int NativeSize {
get { return impl.NativeSize; }
}
public virtual void Dispose ()
{
impl.Destruct (native);
native.Dispose ();
}
}
}

56
QtBindings/Gui/QApplication.cs

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
using System;
using System.Runtime.InteropServices;
using Mono.VisualC.Interop;
using Qt.Core;
namespace Qt.Gui {
public class QApplication : QCoreApplication {
#region Sync with qapplication.h
// C++ interface
protected interface IQApplication : ICppClassOverridable<QApplication>, Base<QCoreApplication.IQCoreApplication> {
void QApplication (CppInstancePtr @this, [MangleAs ("System.Int32&")] IntPtr argc,
[MangleAs (typeof (string[]))] IntPtr argv, int version);
[Virtual] bool macEventFilter(CppInstancePtr @this, IntPtr eventHandlerCallRef, IntPtr eventRef);
// ...
[Virtual] void commitData(CppInstancePtr @this, IntPtr qSessionManager); // was QSessionManager&
[Virtual] void saveState(CppInstancePtr @this, IntPtr qSessionManager); // was QSessionManager&
// ...
[Static] int exec ();
}
// C++ fields
private struct _QApplication {
}
#endregion
private static IQApplication impl = Qt.Libs.QtGui.GetClass<IQApplication,_QApplication,QApplication> ("QApplication");
public QApplication () : base (true)
{
this.native = impl.Alloc (this);
impl.QApplication (native, argc, argv, QGlobal.QT_VERSION);
}
public QApplication (IntPtr native) : base (native)
{
}
public override int Exec ()
{
return impl.exec ();
}
public override int NativeSize {
get { return impl.NativeSize + base.NativeSize; }
}
public override void Dispose ()
{
impl.Destruct (native);
FreeArgcAndArgv ();
native.Dispose ();
}
}
}

25
QtBindings/Libs.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
using System;
using Mono.VisualC.Interop;
using Mono.VisualC.Interop.ABI;
namespace Qt {
internal static class Libs {
public static CppLibrary QtCore = null;
public static CppLibrary QtGui = null;
static Libs ()
{
CppAbi abi;
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
abi = new MsvcAbi ();
else
abi = new ItaniumAbi ();
QtCore = new CppLibrary ("/Library/Frameworks/QtCore.framework/Versions/Current/QtCore", abi);
QtGui = new CppLibrary ("/Library/Frameworks/QtGui.framework/Versions/Current/QtGui", abi);
}
}
}

63
QtBindings/QtBindings.csproj

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Qt</RootNamespace>
<AssemblyName>QtBindings</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="Libs.cs" />
<Compile Include="Gui\QApplication.cs" />
<Compile Include="Core\QGlobal.cs" />
<Compile Include="Core\QCoreApplication.cs" />
<Compile Include="Core\QObject.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mono.VisualC.Interop\Mono.VisualC.Interop.csproj">
<Project>{4A864586-93C5-4DC1-8A80-F094A88506D7}</Project>
<Name>Mono.VisualC.Interop</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="QtBindings.dll.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="Gui\" />
<Folder Include="Core\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<MonoDevelop>
<Properties InternalTargetFrameworkVersion="3.5" />
</MonoDevelop>
</ProjectExtensions>
</Project>

4
QtBindings/QtBindings.dll.config

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
<configuration>
<dllmap dll="QtCore4" os="osx" target="/Library/Frameworks/QtCore.framework/Versions/Current/QtCore" />
<dllmap dll="QtGui4" os="osx" target="/Library/Frameworks/QtGui.framework/Versions/Current/QtGui" />
</configuration>

27
QtTest/AssemblyInfo.cs

@ -0,0 +1,27 @@ @@ -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("QtTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[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("")]

16
QtTest/Main.cs

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
using System;
using Qt.Core;
namespace QtTest {
class MainClass {
public static int Main (string[] args)
{
using (QCoreApplication app = new QCoreApplication ()) {
return app.Exec ();
}
}
}
}

50
QtTest/QtTest.csproj

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{3EE6B50E-58FB-4391-AF01-3FCB1A29B0D7}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>QtTest</RootNamespace>
<AssemblyName>QtTest</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
<Compile Include="AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<MonoDevelop>
<Properties InternalTargetFrameworkVersion="3.5" />
</MonoDevelop>
</ProjectExtensions>
<ItemGroup>
<ProjectReference Include="..\QtBindings\QtBindings.csproj">
<Project>{66212CA6-B8C2-4307-ADDE-DAFEAAB339B9}</Project>
<Name>QtBindings</Name>
</ProjectReference>
</ItemGroup>
</Project>

4
Tests/Support/CSimpleClass.cs

@ -53,6 +53,10 @@ namespace Tests.Support { @@ -53,6 +53,10 @@ namespace Tests.Support {
get { return (IntPtr)native; }
}
public int NativeSize {
get { return impl.NativeSize; }
}
public ICSimpleClass Implementation {
get { return impl; }
}

6
Tests/Support/CppMockObject.cs

@ -28,6 +28,12 @@ namespace Tests.Support { @@ -28,6 +28,12 @@ namespace Tests.Support {
}
}
public int NativeSize {
get {
throw new NotImplementedException ();
}
}
public void Dispose ()
{
throw new System.NotImplementedException ();

Loading…
Cancel
Save