зеркало из https://github.com/mono/CppSharp.git
Initial commit.
git-svn-id: https://mono-soc-2010.googlecode.com/svn/trunk/cppinterop@7 a470b8cb-0e6f-1642-1b45-71e107334c4b
This commit is contained in:
Родитель
389b7dc313
Коммит
f7683a594f
|
@ -0,0 +1,45 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.VisualC.Interop", "Mono.VisualC.Interop\Mono.VisualC.Interop.csproj", "{4A864586-93C5-4DC1-8A80-F094A88506D7}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CPPPOC", "CPPPOC\CPPPOC.csproj", "{7F309FEA-3A3F-40B1-BBF9-A09796253202}"
|
||||
EndProject
|
||||
Project("{2857B73E-F847-4B02-9238-064979017E93}") = "CPPTest", "CPPTest\CPPTest.cproj", "{B01E6282-144E-481A-8E1F-95F708DFBC2D}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Linux|Any CPU = Linux|Any CPU
|
||||
Mac|Any CPU = Mac|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
|
||||
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Linux|Any CPU.Build.0 = Linux|Any CPU
|
||||
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Mac|Any CPU.ActiveCfg = Mac|Any CPU
|
||||
{4A864586-93C5-4DC1-8A80-F094A88506D7}.Mac|Any CPU.Build.0 = Mac|Any CPU
|
||||
{7F309FEA-3A3F-40B1-BBF9-A09796253202}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
|
||||
{7F309FEA-3A3F-40B1-BBF9-A09796253202}.Linux|Any CPU.Build.0 = Linux|Any CPU
|
||||
{7F309FEA-3A3F-40B1-BBF9-A09796253202}.Mac|Any CPU.ActiveCfg = Mac|Any CPU
|
||||
{7F309FEA-3A3F-40B1-BBF9-A09796253202}.Mac|Any CPU.Build.0 = Mac|Any CPU
|
||||
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Linux|Any CPU.ActiveCfg = Linux|Any CPU
|
||||
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Linux|Any CPU.Build.0 = Linux|Any CPU
|
||||
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Mac|Any CPU.ActiveCfg = Mac|Any CPU
|
||||
{B01E6282-144E-481A-8E1F-95F708DFBC2D}.Mac|Any CPU.Build.0 = Mac|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = CPPPOC\CPPPOC.csproj
|
||||
Policies = $0
|
||||
$0.TextStylePolicy = $1
|
||||
$1.TabWidth = 8
|
||||
$1.NoTabsAfterNonTabs = True
|
||||
$1.RemoveTrailingWhitespace = True
|
||||
$1.inheritsSet = VisualStudio
|
||||
$1.inheritsScope = text/plain
|
||||
$1.scope = text/x-csharp
|
||||
$0.CSharpFormattingPolicy = $2
|
||||
$2.inheritsSet = Mono
|
||||
$2.inheritsScope = text/x-csharp
|
||||
$2.scope = text/x-csharp
|
||||
name = CPPInterop
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,29 @@
|
|||
// AssemblyInfo.cs created with MonoDevelop
|
||||
// User: alex at 17:40 03/14/2009
|
||||
//
|
||||
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("CPPPOC")]
|
||||
[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("")]
|
|
@ -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>{7F309FEA-3A3F-40B1-BBF9-A09796253202}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>CPPPOC</AssemblyName>
|
||||
<RootNamespace>CPPPOC</RootNamespace>
|
||||
</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>
|
||||
<Externalconsole>true</Externalconsole>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Mac|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Mac</OutputPath>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</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>
|
||||
<Compile Include="Main.cs" />
|
||||
<Compile Include="AssemblyInfo.cs" />
|
||||
<Compile Include="CSimpleClass.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties InternalTargetFrameworkVersion="3.5" />
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
|
@ -0,0 +1,96 @@
|
|||
// CSimpleClass.cs created with MonoDevelop
|
||||
// User: alex at 17:41 03/14/2009
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Mono.VisualC.Interop;
|
||||
|
||||
namespace CPPPOC {
|
||||
|
||||
public class CSimpleClass : ICppInstance {
|
||||
|
||||
private interface __ICSimpleClass : ICppOverridable<CSimpleClass> {
|
||||
void CSimpleClass(CppInstancePtr ths, int value);
|
||||
void M0(CppInstancePtr ths);
|
||||
[Virtual] void V0(CppInstancePtr ths, int x, int y);
|
||||
void M1(CppInstancePtr ths, int x);
|
||||
[Virtual] void V1(CppInstancePtr ths, int x);
|
||||
void M2(CppInstancePtr ths, int x, int y);
|
||||
[Virtual] void V2(CppInstancePtr ths);
|
||||
CppField<int> value {get;}
|
||||
}
|
||||
private struct __CSimpleClass {
|
||||
public int value;
|
||||
}
|
||||
|
||||
private static __ICSimpleClass _impl;
|
||||
|
||||
public static void Bind(CppLibrary lib) {
|
||||
_impl = lib.GetClass<__ICSimpleClass,__CSimpleClass,CSimpleClass>("CSimpleClass");
|
||||
}
|
||||
|
||||
private CppInstancePtr _native;
|
||||
|
||||
public CSimpleClass(int value) {
|
||||
_native = _impl.Alloc(this);
|
||||
_impl.CSimpleClass(_native, value);
|
||||
}
|
||||
|
||||
public CSimpleClass(IntPtr native) {
|
||||
_native = native;
|
||||
}
|
||||
|
||||
public virtual IntPtr Native {
|
||||
get {
|
||||
return (IntPtr)_native;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int value {
|
||||
get {
|
||||
return _impl.value[_native];
|
||||
}
|
||||
set {
|
||||
_impl.value[_native] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void M0() {
|
||||
_impl.M0(_native);
|
||||
}
|
||||
|
||||
public void M1(int x) {
|
||||
_impl.M1(_native, x);
|
||||
}
|
||||
|
||||
public void M2(int x, int y) {
|
||||
_impl.M2(_native, x, y);
|
||||
}
|
||||
|
||||
[OverrideNative]
|
||||
public virtual void V0(int x, int y) {
|
||||
Console.WriteLine("Managed V0({0}, {1})", x, y);
|
||||
_impl.V0(_native, x, y);
|
||||
}
|
||||
|
||||
[OverrideNative]
|
||||
public virtual void V1(int x) {
|
||||
Console.WriteLine("Managed V1({0})", x);
|
||||
_impl.V1(_native, x);
|
||||
}
|
||||
|
||||
[OverrideNative]
|
||||
public virtual void V2() {
|
||||
Console.WriteLine("Managed V2()");
|
||||
_impl.V2(_native);
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
_impl.Destruct(_native);
|
||||
_native.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// Main.cs created with MonoDevelop
|
||||
// User: alex at 17:40 03/14/2009
|
||||
//
|
||||
using System;
|
||||
using Mono.VisualC.Interop;
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CPPPOC
|
||||
{
|
||||
class MainClass
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
// bind all wrapper classes to their native implementations
|
||||
CppLibrary cppTest = new CppLibrary("CPPTest", new Mono.VisualC.Interop.ABI.Itanium());
|
||||
CSimpleClass.Bind(cppTest);
|
||||
|
||||
CSimpleClass csc1 = new CSimpleClass(CreateCSimpleSubClass(10));
|
||||
CSimpleClass csc2 = new CSimpleClass(2);
|
||||
try {
|
||||
|
||||
csc1.M0();
|
||||
Console.WriteLine("Managed code got value: {0}", csc1.value);
|
||||
csc2.M0();
|
||||
Console.WriteLine("Managed code got value: {0}", csc2.value);
|
||||
|
||||
csc1.value = 100;
|
||||
csc1.V2();
|
||||
|
||||
csc2.value = 200;
|
||||
csc2.V2();
|
||||
|
||||
} finally {
|
||||
DestroyCSimpleSubClass(csc1.Native);
|
||||
csc1.Dispose();
|
||||
csc2.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("CPPTest")]
|
||||
public static extern IntPtr CreateCSimpleSubClass(int value);
|
||||
|
||||
[DllImport("CPPTest")]
|
||||
public static extern void DestroyCSimpleSubClass(IntPtr obj);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* CPPTest.cpp
|
||||
* CPPTest
|
||||
*
|
||||
* Created by Alex Corrado on 3/14/09.
|
||||
* Copyright 2009 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "CPPTest.h"
|
||||
|
||||
CSimpleClass::CSimpleClass(int value) : value(value) {
|
||||
printf("CSimpleClass(%d)\n", value);
|
||||
this->value = value;
|
||||
}
|
||||
|
||||
CSimpleSubClass::CSimpleSubClass(int value) : CSimpleClass(value) {
|
||||
printf("CSimpleSubClass(%d)\n", value);
|
||||
}
|
||||
|
||||
CSimpleClass::~CSimpleClass() {
|
||||
printf("~CSimpleClass\n");
|
||||
}
|
||||
|
||||
void CSimpleClass::M0() {
|
||||
printf("C++/CSimpleClass::M0()\n");
|
||||
V0(value, value + 1);
|
||||
V1(value);
|
||||
V2();
|
||||
}
|
||||
|
||||
void CSimpleClass::V0(int x, int y) {
|
||||
printf("C++/CSimpleClass::V0(%d, %d)\n", x, y);
|
||||
}
|
||||
|
||||
void CSimpleSubClass::V0(int x, int y) {
|
||||
printf("C++/CSimpleSubClass::V0(%d, %d)\n", x, y);
|
||||
}
|
||||
|
||||
void CSimpleClass::M1(int x) {
|
||||
printf("C++/CSimpleClass::M1(%d)\n", x);
|
||||
V0(x, value);
|
||||
V1(x);
|
||||
V2();
|
||||
}
|
||||
|
||||
void CSimpleClass::V1(int x) {
|
||||
printf("C++/CSimpleClass::V1(%d)\n", x);
|
||||
}
|
||||
|
||||
void CSimpleSubClass::V1(int x) {
|
||||
printf("C++/CSimpleSubClass::V1(%d)\n", x);
|
||||
}
|
||||
|
||||
void CSimpleClass::M2(int x, int y) {
|
||||
|
||||
}
|
||||
|
||||
void CSimpleClass::V2() {
|
||||
printf("C++/CSimpleClass::V2() - value: %d\n", value);
|
||||
}
|
||||
|
||||
void CSimpleSubClass::V2() {
|
||||
printf("C++/CSimpleSubClass::V2() - value: %d\n", value);
|
||||
}
|
|
@ -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>{B01E6282-144E-481A-8E1F-95F708DFBC2D}</ProjectGuid>
|
||||
<Compiler>
|
||||
<Compiler ctype="GccCompiler" />
|
||||
</Compiler>
|
||||
<Language>C</Language>
|
||||
<Target>Bin</Target>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineSymbols>DEBUG MONODEVELOP</DefineSymbols>
|
||||
<SourceDirectory>.</SourceDirectory>
|
||||
<OutputName>CPPTest</OutputName>
|
||||
<CompileTarget>SharedLibrary</CompileTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<DefineSymbols>MONODEVELOP</DefineSymbols>
|
||||
<SourceDirectory>.</SourceDirectory>
|
||||
<OptimizationLevel>3</OptimizationLevel>
|
||||
<OutputName>CPPTest</OutputName>
|
||||
<CompileTarget>Bin</CompileTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Mac|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>build\Debug</OutputPath>
|
||||
<ExtraLinkerArguments>-dynamic</ExtraLinkerArguments>
|
||||
<DefineSymbols>DEBUG MONODEVELOP</DefineSymbols>
|
||||
<SourceDirectory>.</SourceDirectory>
|
||||
<CustomCommands>
|
||||
<CustomCommands>
|
||||
<Command type="Build" command="xcodebuild -configuration Debug" workingdir="${ProjectDir}" />
|
||||
<Command type="AfterBuild" command="cp ./build/Debug/libCPPTest.dylib ../CPPPOC/bin/Mac" workingdir="${ProjectDir}" />
|
||||
</CustomCommands>
|
||||
</CustomCommands>
|
||||
<OutputName>libCPPTest.dylib</OutputName>
|
||||
<CompileTarget>Bin</CompileTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux|AnyCPU' ">
|
||||
<OutputPath>build\Debug</OutputPath>
|
||||
<DefineSymbols>DEBUG MONODEVELOP</DefineSymbols>
|
||||
<CompileTarget>SharedLibrary</CompileTarget>
|
||||
<OutputName>libCPPTest.so</OutputName>
|
||||
<CustomCommands>
|
||||
<CustomCommands>
|
||||
<Command type="AfterBuild" command="cp ./build/Debug/libCPPTest.so ../CPPPOC/bin/Linux" workingdir="${ProjectDir}" />
|
||||
</CustomCommands>
|
||||
</CustomCommands>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CPPTest.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CPPTest.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* CPPTest.h
|
||||
* CPPTest
|
||||
*
|
||||
* Created by Alex Corrado on 3/14/09.
|
||||
* Copyright 2009 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CPPTest_
|
||||
#define CPPTest_
|
||||
|
||||
/* The classes below are exported */
|
||||
#pragma GCC visibility push(default)
|
||||
|
||||
class CSimpleClass {
|
||||
public:
|
||||
int value;
|
||||
CSimpleClass(int value);
|
||||
~CSimpleClass();
|
||||
void M0();
|
||||
virtual void V0(int x, int y);
|
||||
void M1(int x);
|
||||
virtual void V1(int x);
|
||||
void M2(int x, int y);
|
||||
virtual void V2();
|
||||
};
|
||||
|
||||
class CSimpleSubClass : CSimpleClass {
|
||||
public:
|
||||
CSimpleSubClass(int value);
|
||||
virtual void V0(int x, int y);
|
||||
virtual void V1(int x);
|
||||
virtual void V2();
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
CSimpleSubClass* CreateCSimpleSubClass(int value) {
|
||||
return new CSimpleSubClass(value);
|
||||
}
|
||||
void DestroyCSimpleSubClass(CSimpleSubClass* obj) {
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC visibility pop
|
||||
#endif
|
|
@ -0,0 +1,487 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.ABI.CppAbi.cs: Represents an abstract C++ ABI
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop.ABI {
|
||||
|
||||
//TODO: Exception handling, operator overloading etc.
|
||||
//TODO: Allow interface to override default calling convention
|
||||
public abstract class CppAbi {
|
||||
|
||||
protected ModuleBuilder implModule;
|
||||
protected TypeBuilder implType;
|
||||
|
||||
protected Type interfaceType, layoutType, wrapperType;
|
||||
protected string library, className;
|
||||
|
||||
protected FieldBuilder vtableField;
|
||||
protected ILGenerator ctorIL;
|
||||
|
||||
public virtual Iface ImplementClass<Iface, NLayout> (ModuleBuilder implModule, Type wrapperType, string lib, string className)
|
||||
where NLayout : struct
|
||||
//where Iface : ICppNativeInterface or ICppNativeInterfaceManaged
|
||||
{
|
||||
this.implModule = implModule;
|
||||
this.library = lib;
|
||||
this.className = className;
|
||||
this.interfaceType = typeof (Iface);
|
||||
this.layoutType = typeof (NLayout);
|
||||
this.wrapperType = wrapperType;
|
||||
|
||||
MethodInfo[] methods = interfaceType.GetMethods ();
|
||||
|
||||
// sort methods into declaration order
|
||||
// TODO: This is kinda kludgy isn't it?
|
||||
Array.Sort (methods, (x, y) => x.MetadataToken - y.MetadataToken);
|
||||
|
||||
int vtableIndex = 0;
|
||||
List<Delegate> vtableDelegates = new List<Delegate>();
|
||||
|
||||
// Implement all methods
|
||||
for (int i = 0; i < methods.Length; i++) {
|
||||
// Skip over special methods like property accessors -- properties will be handled later
|
||||
if (methods [i].IsSpecialName)
|
||||
continue;
|
||||
|
||||
DefineMethod (methods [i], vtableIndex);
|
||||
|
||||
if (!Modifiers.IsVirtual (methods [i]))
|
||||
continue;
|
||||
|
||||
MethodInfo overrideTarget = FindManagedOverrideTarget (methods [i], VTable.BindOverridesOnly);
|
||||
if (overrideTarget != null)
|
||||
vtableDelegates.Insert(vtableIndex, GetManagedOverrideTrampoline (methods [i], overrideTarget));
|
||||
|
||||
vtableIndex++;
|
||||
}
|
||||
|
||||
DefineImplType ();
|
||||
|
||||
// Implement all properties
|
||||
foreach (var property in interfaceType.GetProperties ())
|
||||
DefineFieldProperty (property);
|
||||
|
||||
|
||||
ctorIL.Emit (OpCodes.Ret);
|
||||
return (Iface)Activator.CreateInstance (implType.CreateType (), vtable);
|
||||
}
|
||||
|
||||
// These methods might be more commonly overridden for a given C++ ABI:
|
||||
|
||||
public virtual MethodType GetMethodType (MethodInfo imethod)
|
||||
{
|
||||
if (imethod.Name.Equals (className))
|
||||
return MethodType.NativeCtor;
|
||||
else if (imethod.Name.Equals ("Alloc"))
|
||||
return MethodType.ManagedAlloc;
|
||||
else if (imethod.Name.Equals ("Destruct"))
|
||||
return MethodType.NativeDtor;
|
||||
|
||||
return MethodType.Native;
|
||||
}
|
||||
|
||||
public virtual int FieldOffsetPadding {
|
||||
get { return Marshal.SizeOf (typeof (IntPtr)); }
|
||||
}
|
||||
|
||||
protected virtual int NativeSize {
|
||||
get {
|
||||
// By default: native size = C++ class size + field offset padding (usually just vtable pointer)
|
||||
// TODO: Only include vtable ptr if there are virtual functions? Here I guess it doesn't really matter,
|
||||
// we're just allocing extra memory.
|
||||
return Marshal.SizeOf (layoutType) + FieldOffsetPadding;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual VTable MakeVTable (Delegate[] overrides)
|
||||
{
|
||||
return new VTableManaged (overrides);
|
||||
}
|
||||
|
||||
// The members below must be implemented for a given C++ ABI:
|
||||
|
||||
public abstract string GetMangledMethodName (MethodInfo methodInfo);
|
||||
public abstract CallingConvention DefaultCallingConvention { get; }
|
||||
|
||||
protected virtual void DefineImplType ()
|
||||
{
|
||||
|
||||
implType = implModule.DefineType (implModule.Name + "_" + interfaceType.Name + "_Impl",
|
||||
TypeAttributes.Class | TypeAttributes.Sealed);
|
||||
implType.AddInterfaceImplementation (interfaceType);
|
||||
|
||||
vtableField = implType.DefineField ("_vtable", typeof (VTable), FieldAttributes.InitOnly | FieldAttributes.Private);
|
||||
ConstructorBuilder ctor = implType.DefineConstructor (MethodAttributes.Public, CallingConventions.Standard,
|
||||
new Type[] { typeof (VTable) });
|
||||
|
||||
ctorIL = ctor.GetILGenerator ();
|
||||
|
||||
// this._vtable = (VTable passed to constructor)
|
||||
ctorIL.Emit (OpCodes.Ldarg_0);
|
||||
ctorIL.Emit (OpCodes.Ldarg_1);
|
||||
ctorIL.Emit (OpCodes.Stfld, vtableField);
|
||||
}
|
||||
|
||||
protected virtual MethodBuilder DefineMethod (MethodInfo interfaceMethod, int index)
|
||||
{
|
||||
// 0. Introspect method
|
||||
MethodType methodType = GetMethodType (interfaceMethod);
|
||||
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, false);
|
||||
|
||||
// 1. Generate managed trampoline to call native method
|
||||
MethodBuilder trampoline = GetMethodBuilder (interfaceMethod);
|
||||
ILGenerator il = trampoline.GetILGenerator ();
|
||||
|
||||
if (methodType == MethodType.ManagedAlloc) {
|
||||
EmitManagedAlloc (il);
|
||||
il.Emit (OpCodes.Ret);
|
||||
return trampoline;
|
||||
}
|
||||
|
||||
// 2. Load the native C++ instance pointer
|
||||
LocalBuilder cppInstancePtr, nativePtr;
|
||||
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)) {
|
||||
nativeMethod = null;
|
||||
else
|
||||
nativeMethod = GetPInvokeForMethod (interfaceMethod);
|
||||
|
||||
switch (methodType) {
|
||||
case MethodType.NativeCtor:
|
||||
EmitConstruct (il, nativeMethod, parameterTypes.Length, nativePtr);
|
||||
break;
|
||||
|
||||
case MethodType.NativeDtor:
|
||||
EmitDestruct (il, nativeMethod, parameterTypes.Length, nativePtr);
|
||||
break;
|
||||
|
||||
default: // regular native method
|
||||
EmitCallNative (il, nativeMethod, parameterTypes.Length, nativePtr);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
|
||||
|
||||
il.Emit (OpCodes.Ret);
|
||||
return trampoline;
|
||||
}
|
||||
|
||||
protected virtual PropertyBuilder DefineFieldProperty (PropertyInfo property)
|
||||
{
|
||||
if (property.CanWrite)
|
||||
throw new InvalidProgramException ("Properties in C++ interface must be read-only.");
|
||||
|
||||
MethodInfo imethod = property.GetGetMethod ();
|
||||
string methodName = imethod.Name;
|
||||
string propName = property.Name;
|
||||
Type retType = imethod.ReturnType;
|
||||
|
||||
if ((!retType.IsGenericType) || (!retType.GetGenericTypeDefinition ().Equals (typeof (CppField<>))))
|
||||
throw new InvalidProgramException ("Properties in C++ interface can only be of type CppField.");
|
||||
|
||||
PropertyBuilder fieldProp = implType.DefineProperty (propName, PropertyAttributes.None, retType, Type.EmptyTypes);
|
||||
FieldBuilder fieldData = implType.DefineField ("__" + propName + "_Data", retType, FieldAttributes.InitOnly | FieldAttributes.Private);
|
||||
|
||||
// init our field data with a new instance of CppField
|
||||
// first, get field offset
|
||||
ctorIL.Emit (OpCodes.Ldarg_0);
|
||||
|
||||
/* TODO: Code prolly should not emit hardcoded offsets n such, in case we end up saving these assemblies in the future.
|
||||
* Something more like this perhaps? (need to figure out how to get field offset padding into this)
|
||||
* ctorIL.Emit(OpCodes.Ldtoken, nativeLayout);
|
||||
* ctorIL.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
|
||||
* ctorIL.Emit(OpCodes.Ldstr, propName);
|
||||
* ctorIL.Emit(OpCodes.Call, typeof(Marshal).GetMethod("OffsetOf"));
|
||||
*/
|
||||
int fieldOffset = ((int)Marshal.OffsetOf (layoutType, propName)) + FieldOffsetPadding;
|
||||
ctorIL.Emit (OpCodes.Ldc_I4, fieldOffset);
|
||||
ctorIL.Emit (OpCodes.Newobj, retType.GetConstructor (new Type[] { typeof(int) }));
|
||||
|
||||
ctorIL.Emit (OpCodes.Stfld, fieldData);
|
||||
|
||||
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
|
||||
MethodBuilder fieldGetter = implType.DefineMethod (methodName, methodAttr, retType, Type.EmptyTypes);
|
||||
ILGenerator il = fieldGetter.GetILGenerator ();
|
||||
|
||||
il.Emit (OpCodes.Ldarg_0);
|
||||
il.Emit (OpCodes.Ldfld, fieldData);
|
||||
il.Emit (OpCodes.Ret);
|
||||
|
||||
fieldProp.SetGetMethod (fieldGetter);
|
||||
|
||||
return fieldProp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the managed trampoline that will be invoked from the vtable by native C++ code when overriding
|
||||
* the specified C++ virtual method with the specified managed one.
|
||||
*/
|
||||
protected virtual Delegate GetManagedOverrideTrampoline (MethodInfo interfaceMethod, MethodInfo targetMethod)
|
||||
{
|
||||
Type delegateType = Util.GetDelegateTypeForMethodInfo (implModule, interfaceMethod);
|
||||
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, true);
|
||||
|
||||
// TODO: According to http://msdn.microsoft.com/en-us/library/w16z8yc4.aspx
|
||||
// The dynamic method created with this constructor has access to public and internal members of all the types contained in module m.
|
||||
// This does not appear to hold true, so we also disable JIT visibility checks.
|
||||
DynamicMethod trampolineIn = new DynamicMethod (wrapperType.Name + "_" + interfaceMethod.Name + "_FromNative", interfaceMethod.ReturnType,
|
||||
parameterTypes, typeof (CppInstancePtr).Module, true);
|
||||
|
||||
ILGenerator il = trampolineIn.GetILGenerator ();
|
||||
|
||||
// for static methods:
|
||||
OpCode callInstruction = OpCodes.Call;
|
||||
int argLoadStart = 0;
|
||||
|
||||
// for instance methods, we need an instance to call them on!
|
||||
if (!targetMethod.IsStatic) {
|
||||
callInstruction = OpCodes.Callvirt;
|
||||
argLoadStart = 1;
|
||||
|
||||
il.Emit (OpCodes.Ldarg_0);
|
||||
il.Emit (OpCodes.Ldc_I4, NativeSize);
|
||||
|
||||
MethodInfo getManagedObj = typeof (CppInstancePtr).GetMethod ("GetManaged", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod (wrapperType);
|
||||
il.Emit (OpCodes.Call, getManagedObj);
|
||||
}
|
||||
|
||||
for (int i = argLoadStart; i < parameterTypes.Length; i++) {
|
||||
il.Emit (OpCodes.Ldarg, i);
|
||||
}
|
||||
il.Emit (OpCodes.Tailcall);
|
||||
il.Emit (callInstruction, targetMethod);
|
||||
il.Emit (OpCodes.Ret);
|
||||
|
||||
return trampolineIn.CreateDelegate (delegateType);
|
||||
}
|
||||
|
||||
protected virtual MethodInfo FindManagedOverrideTarget (MethodInfo interfaceMethod, MemberFilter filter)
|
||||
{
|
||||
MemberInfo[] possibleMembers = wrapperType.FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.NonPublic |
|
||||
BindingFlags.Instance | BindingFlags.Static, filter, interfaceMethod);
|
||||
|
||||
if (possibleMembers.Length > 1)
|
||||
throw new InvalidProgramException ("More than one possible override found when binding virtual method: " + interfaceMethod.Name);
|
||||
else if (possibleMembers.Length == 0)
|
||||
return null;
|
||||
|
||||
return (MethodInfo)possibleMembers [0];
|
||||
}
|
||||
/**
|
||||
* Defines a new MethodBuilder with the same signature as the passed MethodInfo
|
||||
*/
|
||||
protected virtual MethodBuilder GetMethodBuilder (MethodInfo interfaceMethod)
|
||||
{
|
||||
|
||||
Type[] parameterTypes = Util.GetMethodParameterTypes (interfaceMethod, false);
|
||||
MethodBuilder methodBuilder = implType.DefineMethod (interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
interfaceMethod.ReturnType, parameterTypes);
|
||||
|
||||
return methodBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a new MethodBuilder that calls the specified C++ (non-virtual) method using its mangled name
|
||||
*/
|
||||
protected virtual MethodBuilder GetPInvokeForMethod (MethodInfo signature)
|
||||
{
|
||||
string entryPoint = GetMangledMethodName (signature);
|
||||
if (entryPoint == null)
|
||||
throw new NotSupportedException ("Could not mangle method name.");
|
||||
|
||||
Type[] parameterTypes = Util.GetMethodParameterTypes (signature, true);
|
||||
|
||||
MethodBuilder builder = implType.DefinePInvokeMethod ("__$" + signature.Name + "_Impl", library, entryPoint,
|
||||
MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.PinvokeImpl,
|
||||
CallingConventions.Any, signature.ReturnType, parameterTypes,
|
||||
DefaultCallingConvention, CharSet.Ansi);
|
||||
|
||||
builder.SetImplementationFlags (builder.GetMethodImplementationFlags () | MethodImplAttributes.PreserveSig);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
|
||||
//TODO: Do not hard-emit native size in case assembly is saved?
|
||||
il.Emit (OpCodes.Ldc_I4, NativeSize);
|
||||
|
||||
if (wrapperType != null) {
|
||||
// load managed object
|
||||
il.Emit (OpCodes.Ldarg_1);
|
||||
|
||||
//new CppInstancePtr (Abi.GetNativeSize (typeof (NativeLayout)), managedWrapper);
|
||||
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
|
||||
new Type[] { typeof (int), typeof (object) }, null));
|
||||
} else
|
||||
il.Emit (OpCodes.Newobj, typeof (CppInstancePtr).GetConstructor (BindingFlags.Instance | BindingFlags.NonPublic, null,
|
||||
new Type[] { typeof (int) }, null));
|
||||
}
|
||||
|
||||
protected virtual void EmitConstruct (ILGenerator il, MethodInfo nativeMethod, int parameterCount, LocalBuilder nativePtr)
|
||||
{
|
||||
EmitCallNative (il, nativeMethod, parameterCount, nativePtr);
|
||||
EmitInitVTable (il, nativePtr);
|
||||
}
|
||||
|
||||
protected virtual void EmitDestruct (ILGenerator il, MethodInfo nativeMethod, int parameterCount, LocalBuilder nativePtr)
|
||||
{
|
||||
EmitResetVTable (il, nativePtr);
|
||||
EmitCallNative (il, nativeMethod, parameterCount, nativePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits IL to call the native method. nativeMethod should be either a method obtained by
|
||||
* GetPInvokeForMethod or the MethodInfo of a vtable method.
|
||||
* To complete method, emit OpCodes.Ret.
|
||||
*/
|
||||
protected virtual void EmitCallNative (ILGenerator il, MethodInfo nativeMethod, int parameterCount, LocalBuilder nativePtr)
|
||||
{
|
||||
il.Emit (OpCodes.Ldloc_S, nativePtr);
|
||||
for (int i = 2; i <= parameterCount; i++)
|
||||
il.Emit (OpCodes.Ldarg, i);
|
||||
|
||||
il.Emit (OpCodes.Call, nativeMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits IL to set the vtable pointer of the instance (if class has a vtable).
|
||||
* This should usually happen in the managed wrapper of the C++ instance constructor.
|
||||
*/
|
||||
protected virtual void EmitInitVTable (ILGenerator il, LocalBuilder nativePtr)
|
||||
{
|
||||
// this._vtable.InitInstance (nativePtr);
|
||||
il.Emit (OpCodes.Ldarg_0);
|
||||
il.Emit (OpCodes.Ldfld, vtableField);
|
||||
il.Emit (OpCodes.Ldloc_S, nativePtr);
|
||||
EmitVTableOp (il, typeof (VTable).GetMethod ("InitInstance"), 2, false);
|
||||
}
|
||||
|
||||
protected virtual void EmitResetVTable (ILGenerator il, LocalBuilder nativePtr)
|
||||
{
|
||||
// this._vtable.ResetInstance (nativePtr);
|
||||
il.Emit (OpCodes.Ldarg_0);
|
||||
il.Emit (OpCodes.Ldfld, vtableField);
|
||||
il.Emit (OpCodes.Ldloc_S, nativePtr);
|
||||
EmitVTableOp (il, typeof(VTable).GetMethod ("ResetInstance"), 2, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility function to emit the IL for a vtable-dependant operation.
|
||||
* In other words, classes with no virtual methods will not have vtables,
|
||||
* so this method emits code to check for that and either throw an exception
|
||||
* or do nothing if no vtable exists. To use, push the arguments to the method you
|
||||
* want to call and pass the stackHeight for the call. If no vtable exists, this method
|
||||
* will emit code to pop the arguments off the stack.
|
||||
*/
|
||||
protected virtual void EmitVTableOp(ILGenerator il, MethodInfo method, int stackHeight, bool throwOnNoVTable)
|
||||
{
|
||||
// prepare a jump; do not call vtable method if no vtable
|
||||
Label noVirt = il.DefineLabel ();
|
||||
Label dontPushOrThrow = il.DefineLabel ();
|
||||
|
||||
il.Emit (OpCodes.Ldarg_0); // load this
|
||||
il.Emit (OpCodes.Ldfld, vtableField); // load this._vtable
|
||||
il.Emit (OpCodes.Brfalse_S, noVirt); // if (vtableInfo == null) goto noVirt
|
||||
|
||||
il.Emit (OpCodes.Callvirt, method); // call method
|
||||
il.Emit (OpCodes.Br_S, dontPushOrThrow); // goto dontPushOrThrow
|
||||
|
||||
il.MarkLabel (noVirt);
|
||||
// noVirt:
|
||||
// since there is no vtable, we did not make the method call.
|
||||
// pop arguments
|
||||
for (int i = 0; i < stackHeight; i++)
|
||||
il.Emit (OpCodes.Pop);
|
||||
|
||||
// if the method was supposed to return a value, we must
|
||||
// still push something onto the stack
|
||||
// TODO: This is a kludge. What about value types?
|
||||
if (!method.ReturnType.Equals (typeof (void)))
|
||||
il.Emit (OpCodes.Ldnull);
|
||||
|
||||
if (throwOnNoVTable) {
|
||||
il.Emit (OpCodes.Ldstr, "Native class has no VTable.");
|
||||
il.Emit (OpCodes.Newobj, typeof (InvalidOperationException).GetConstructor(new Type[] {typeof (string)}));
|
||||
il.Emit (OpCodes.Throw);
|
||||
}
|
||||
|
||||
il.MarkLabel (dontPushOrThrow);
|
||||
}
|
||||
|
||||
protected virtual void EmitLoadInstancePtr (ILGenerator il, Type firstParamType, out LocalBuilder cppip, out LocalBuilder native)
|
||||
{
|
||||
cppip = null;
|
||||
native = il.DeclareLocal (typeof (IntPtr));
|
||||
|
||||
il.Emit (OpCodes.Ldarg_1);
|
||||
if (firstParamType.Equals (typeof (CppInstancePtr))) {
|
||||
cppip = il.DeclareLocal (typeof (CppInstancePtr));
|
||||
il.Emit (OpCodes.Stloc_S, cppip);
|
||||
il.Emit (OpCodes.Ldloca_S, cppip);
|
||||
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("Native").GetGetMethod ());
|
||||
il.Emit (OpCodes.Stloc_S, native);
|
||||
} 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.");
|
||||
}
|
||||
|
||||
protected virtual void EmitCheckManagedAlloc (ILGenerator il, LocalBuilder cppip)
|
||||
{
|
||||
// make sure we were allocated by managed code
|
||||
// if not, return
|
||||
Label managedAlloc = il.DefineLabel ();
|
||||
il.Emit (OpCodes.Ldloca_S, cppip);
|
||||
il.Emit (OpCodes.Call, typeof (CppInstancePtr).GetProperty ("IsManagedAlloc").GetGetMethod ());
|
||||
il.Emit (OpCodes.Brtrue_S, managedAlloc);
|
||||
il.Emit (OpCodes.Ret);
|
||||
il.MarkLabel (managedAlloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* throw ObjectDisposedException if we have a null pointer for native
|
||||
* however, allow destructor to be called even if we're disposed (just return immediately)
|
||||
*/
|
||||
protected virtual void EmitCheckDisposed (ILGenerator il, LocalBuilder native, MethodType methodType)
|
||||
{
|
||||
Label validRef = il.DefineLabel ();
|
||||
il.Emit (OpCodes.Ldloc_S, native);
|
||||
il.Emit (OpCodes.Brtrue_S, validRef);
|
||||
if (methodType == MethodType.NativeDtor) {
|
||||
il.Emit (OpCodes.Ret);
|
||||
il.MarkLabel (validRef);
|
||||
} else {
|
||||
il.Emit (OpCodes.Ldstr, String.Empty);
|
||||
il.Emit (OpCodes.Newobj, typeof (ObjectDisposedException).GetConstructor (new Type[] { typeof(string) }));
|
||||
il.Emit (OpCodes.Throw);
|
||||
il.MarkLabel (validRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop.ABI {
|
||||
|
||||
public class Itanium : CppAbi {
|
||||
|
||||
public Itanium() {}
|
||||
|
||||
public override CallingConvention DefaultCallingConvention {
|
||||
get {
|
||||
return CallingConvention.Cdecl;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetMangledMethodName(MethodInfo methodInfo) {
|
||||
string methodName = methodInfo.Name;
|
||||
MethodType methodType = GetMethodType(methodInfo);
|
||||
ParameterInfo[] parameters = methodInfo.GetParameters();
|
||||
|
||||
StringBuilder nm = new StringBuilder("_ZN", 30);
|
||||
nm.Append(className.Length).Append(className);
|
||||
|
||||
switch (methodType) {
|
||||
|
||||
case MethodType.NativeCtor:
|
||||
nm.Append("C1");
|
||||
break;
|
||||
|
||||
case MethodType.NativeDtor:
|
||||
nm.Append("D1");
|
||||
break;
|
||||
|
||||
default:
|
||||
nm.Append(methodName.Length).Append(methodName);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
nm.Append("E");
|
||||
|
||||
if (parameters.Length == 1) { //only the C++ "this" object
|
||||
nm.Append("v");
|
||||
} else for (int i = 1; i < parameters.Length; i++) {
|
||||
nm.Append(GetTypeCode(parameters[i].ParameterType));
|
||||
}
|
||||
|
||||
return nm.ToString();
|
||||
}
|
||||
|
||||
protected virtual string GetTypeCode(Type t) {
|
||||
if (t.Equals(typeof(int))) return "i";
|
||||
throw new NotSupportedException("Unsupported parameter type: " + t.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
namespace Mono.VisualC.Interop {
|
||||
public enum MethodType {
|
||||
Native,
|
||||
NativeCtor,
|
||||
NativeDtor,
|
||||
ManagedAlloc
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.ABI.VTable.cs: abstract vtable
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop.ABI {
|
||||
public abstract class VTable : IDisposable {
|
||||
protected IntPtr basePtr, vtPtr;
|
||||
|
||||
public virtual int EntryCount { get; protected set; }
|
||||
|
||||
public abstract int EntrySize { get; }
|
||||
public abstract void EmitVirtualCall (ILGenerator il, IntPtr native, int index);
|
||||
|
||||
// Creates a new VTable
|
||||
public VTable (Delegate[] overrides)
|
||||
{
|
||||
EntryCount = overrides.Length;
|
||||
|
||||
int vtableSize = EntryCount * EntrySize;
|
||||
IntPtr vtEntryPtr;
|
||||
|
||||
basePtr = IntPtr.Zero;
|
||||
vtPtr = Marshal.AllocHGlobal (vtableSize);
|
||||
|
||||
try {
|
||||
int offset = 0;
|
||||
for (int i = 0; i < EntryCount; i++) {
|
||||
|
||||
if (overrides [i] != null) // managed override
|
||||
vtEntryPtr = Marshal.GetFunctionPointerForDelegate (overrides [i]);
|
||||
else
|
||||
vtEntryPtr = IntPtr.Zero;
|
||||
|
||||
Marshal.WriteIntPtr (vtPtr, offset, vtEntryPtr);
|
||||
offset += EntrySize;
|
||||
}
|
||||
} catch {
|
||||
|
||||
Marshal.FreeHGlobal (vtPtr);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void InitInstance (IntPtr instance)
|
||||
{
|
||||
if (basePtr == IntPtr.Zero) {
|
||||
basePtr = Marshal.ReadIntPtr (instance);
|
||||
|
||||
int offset = 0;
|
||||
for (int i = 0; i < EntryCount; i++) {
|
||||
|
||||
IntPtr vtEntryPtr = Marshal.ReadIntPtr (vtPtr, offset);
|
||||
if (vtEntryPtr == IntPtr.Zero)
|
||||
Marshal.WriteIntPtr (vtPtr, offset, Marshal.ReadIntPtr (basePtr, offset));
|
||||
|
||||
offset += EntrySize;
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.WriteIntPtr (instance, vtPtr);
|
||||
}
|
||||
|
||||
public virtual void ResetInstance (IntPtr instance)
|
||||
{
|
||||
Marshal.WriteIntPtr (instance, basePtr);
|
||||
}
|
||||
|
||||
public IntPtr Pointer {
|
||||
get { return vtPtr; }
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (vtPtr != IntPtr.Zero) {
|
||||
Marshal.FreeHGlobal (vtPtr);
|
||||
vtPtr = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This WON'T usually be called because VTables are associated with classes
|
||||
// and managed C++ class wrappers are staticly held?
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
~VTable ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
|
||||
public static bool BindOverridesOnly (MemberInfo member, object obj)
|
||||
{
|
||||
bool result = BindAny (member, obj);
|
||||
if (member.GetCustomAttributes (typeof (OverrideNativeAttribute), true).Length != 1)
|
||||
return false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool BindAny (MemberInfo member, object obj)
|
||||
{
|
||||
MethodInfo imethod = (MethodInfo) obj;
|
||||
MethodInfo candidate = (MethodInfo) member;
|
||||
|
||||
if (!candidate.Name.Equals (imethod.Name))
|
||||
return false;
|
||||
|
||||
ParameterInfo[] invokeParams = imethod.GetParameters ();
|
||||
ParameterInfo[] methodParams = candidate.GetParameters ();
|
||||
|
||||
if (invokeParams.Length == methodParams.Length) {
|
||||
for (int i = 0; i < invokeParams.Length; i++) {
|
||||
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i].ParameterType))
|
||||
return false;
|
||||
}
|
||||
} else if (invokeParams.Length == methodParams.Length + 1) {
|
||||
for (int i = 1; i < invokeParams.Length; i++) {
|
||||
if (!invokeParams [i].ParameterType.IsAssignableFrom (methodParams [i - 1].ParameterType))
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.ABI.VTableCOM.cs: vtable implementation based on COM interop (reqiures mono patch)
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop.ABI {
|
||||
public class VTableCOM : VTable {
|
||||
|
||||
public VTableCOM (Delegate[] entries) : base(entries)
|
||||
{
|
||||
}
|
||||
|
||||
public override int EntrySize {
|
||||
get { return Marshal.SizeOf (typeof (IntPtr)); }
|
||||
}
|
||||
|
||||
public override T GetDelegateForNative<T> (IntPtr native, int index)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.ABI.VTableManaged.cs: Managed vtable implementation
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop.ABI {
|
||||
public class VTableManaged : VTable {
|
||||
|
||||
public VTableManaged (Delegate[] entries) : base(entries)
|
||||
{
|
||||
}
|
||||
|
||||
public override int EntrySize {
|
||||
get { return Marshal.SizeOf (typeof (IntPtr)); }
|
||||
}
|
||||
|
||||
public override T GetDelegateForNative<T> (IntPtr native, int index)
|
||||
{
|
||||
IntPtr vtable = Marshal.ReadIntPtr (native);
|
||||
if (vtable == vtPtr) // do not return managed overrides
|
||||
vtable = basePtr;
|
||||
|
||||
IntPtr ftnptr = Marshal.ReadIntPtr (vtable, index * EntrySize);
|
||||
if (ftnptr == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
Delegate del = Marshal.GetDelegateForFunctionPointer (ftnptr, typeof (T));
|
||||
return del as T;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
protected static Type GetNativeLayoutType(MethodInfo thisMethod) {
|
||||
ParameterInfo[] parameters = thisMethod.GetParameters();
|
||||
if (parameters.Length < 1) return null;
|
||||
|
||||
Type nativeLayoutType = parameters[0].ParameterType.GetElementType();
|
||||
return nativeLayoutType;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// AssemblyInfo.cs created with MonoDevelop
|
||||
// User: alex at 21:36 03/13/2009
|
||||
//
|
||||
using System;
|
||||
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("Mono.VisualC.Interop")]
|
||||
[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("")]
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
// TODO: This will not work if we ever support saving these assemblies
|
||||
[assembly: InternalsVisibleTo("__CPPLibraryImplAssembly")]
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.Attributes.cs
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Mono.VisualC.Interop {
|
||||
[AttributeUsage (AttributeTargets.Method)]
|
||||
public class VirtualAttribute : Attribute {}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Method)]
|
||||
public class OverrideNativeAttribute : Attribute {}
|
||||
|
||||
public static class Modifiers {
|
||||
|
||||
public static bool IsVirtual (MethodInfo method)
|
||||
{
|
||||
return method.IsDefined (typeof (VirtualAttribute), false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.CppField.cs: Represents a field in a native C++ object
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop
|
||||
{
|
||||
public class CppField<T>
|
||||
{
|
||||
private int fieldOffset;
|
||||
|
||||
public CppField (int fieldOffset)
|
||||
{
|
||||
this.fieldOffset = fieldOffset;
|
||||
}
|
||||
|
||||
public T this [CppInstancePtr ip] {
|
||||
get {
|
||||
Type retType = typeof(T);
|
||||
object retVal;
|
||||
if (retType.Equals(typeof(Byte)))
|
||||
retVal = Marshal.ReadByte(ip.Native, fieldOffset);
|
||||
else if (retType.Equals(typeof(Int16)))
|
||||
retVal = Marshal.ReadInt16(ip.Native, fieldOffset);
|
||||
else if (retType.Equals(typeof(Int32)))
|
||||
retVal = Marshal.ReadInt32(ip.Native, fieldOffset);
|
||||
else throw new NotImplementedException("Cannot read C++ fields of type " + retType.Name);
|
||||
|
||||
return (T)retVal;
|
||||
}
|
||||
set {
|
||||
Type setType = typeof(T);
|
||||
object setVal = value;
|
||||
if (setType.Equals(typeof(Byte)))
|
||||
Marshal.WriteByte(ip.Native, fieldOffset, (byte)setVal);
|
||||
else if (setType.Equals(typeof(Int16)))
|
||||
Marshal.WriteInt16(ip.Native, fieldOffset, (Int16)setVal);
|
||||
else if (setType.Equals(typeof(Int32)))
|
||||
Marshal.WriteInt32(ip.Native, fieldOffset, (Int32)setVal);
|
||||
else throw new NotImplementedException("Cannot write C++ fields of type " + setType.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.CppInstancePtr.cs: Represents a pointer to a native C++ instance
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.VisualC.Interop {
|
||||
public struct CppInstancePtr : ICppInstance {
|
||||
private IntPtr ptr;
|
||||
private bool manageMemory;
|
||||
|
||||
// Alloc a new C++ instance
|
||||
internal CppInstancePtr (int nativeSize, object managedWrapper)
|
||||
{
|
||||
// Under the hood, we're secretly subclassing this C++ class to store a
|
||||
// handle to the managed wrapper.
|
||||
ptr = Marshal.AllocHGlobal (nativeSize + Marshal.SizeOf (typeof (IntPtr)));
|
||||
|
||||
IntPtr handlePtr = GetGCHandle (managedWrapper);
|
||||
Marshal.WriteIntPtr (ptr, nativeSize, handlePtr);
|
||||
|
||||
manageMemory = true;
|
||||
}
|
||||
|
||||
// Alloc a new C++ instance when there is no managed wrapper.
|
||||
internal CppInstancePtr (int nativeSize)
|
||||
{
|
||||
ptr = Marshal.AllocHGlobal (nativeSize);
|
||||
manageMemory = true;
|
||||
}
|
||||
|
||||
// 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");
|
||||
|
||||
ptr = native;
|
||||
manageMemory = false;
|
||||
}
|
||||
|
||||
// Provide casts to/from IntPtr:
|
||||
public static implicit operator CppInstancePtr (IntPtr native)
|
||||
{
|
||||
return new CppInstancePtr (native);
|
||||
}
|
||||
|
||||
// cast from CppInstancePtr -> IntPtr is explicit because we lose information
|
||||
public static explicit operator IntPtr (CppInstancePtr ip)
|
||||
{
|
||||
return ip.Native;
|
||||
}
|
||||
|
||||
public IntPtr Native {
|
||||
get {
|
||||
if (ptr == IntPtr.Zero)
|
||||
throw new ObjectDisposedException ("CppInstancePtr");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsManagedAlloc {
|
||||
get { return manageMemory; }
|
||||
}
|
||||
|
||||
internal static IntPtr GetGCHandle (object managedWrapper)
|
||||
{
|
||||
// TODO: Dispose() should probably be called at some point on this GCHandle.
|
||||
GCHandle handle = GCHandle.Alloc (managedWrapper, GCHandleType.Normal);
|
||||
return GCHandle.ToIntPtr (handle);
|
||||
}
|
||||
|
||||
// WARNING! This method is not safe. DO NOT call
|
||||
// if we do not KNOW that this instance is managed.
|
||||
internal static T GetManaged<T> (IntPtr native, int nativeSize) where T : class
|
||||
{
|
||||
|
||||
IntPtr handlePtr = Marshal.ReadIntPtr (native, nativeSize);
|
||||
GCHandle handle = GCHandle.FromIntPtr (handlePtr);
|
||||
|
||||
return handle.Target as T;
|
||||
}
|
||||
|
||||
// TODO: Free GCHandle?
|
||||
public void Dispose ()
|
||||
{
|
||||
if (manageMemory && ptr != IntPtr.Zero)
|
||||
Marshal.FreeHGlobal (ptr);
|
||||
|
||||
ptr = IntPtr.Zero;
|
||||
manageMemory = false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.CppLibrary.cs: Represents a native C++ library for interop
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
using Mono.VisualC.Interop.ABI;
|
||||
|
||||
namespace Mono.VisualC.Interop
|
||||
{
|
||||
|
||||
public sealed class CppLibrary
|
||||
{
|
||||
private static AssemblyBuilder interopAssembly;
|
||||
private static ModuleBuilder interopModule;
|
||||
|
||||
private CppAbi abi;
|
||||
private string name;
|
||||
|
||||
static CppLibrary ()
|
||||
{
|
||||
AssemblyName assemblyName = new AssemblyName ("__CPPLibraryImplAssembly");
|
||||
string moduleName = "__CPPLibraryImplModule";
|
||||
|
||||
interopAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly (assemblyName, AssemblyBuilderAccess.Run);
|
||||
interopModule = interopAssembly.DefineDynamicModule (moduleName);
|
||||
}
|
||||
|
||||
public CppLibrary (string name, CppAbi abi)
|
||||
{
|
||||
|
||||
if (name == null)
|
||||
throw new ArgumentNullException ("Name cannot be NULL.");
|
||||
if (abi == null)
|
||||
throw new ArgumentNullException ("Abi cannot be NULL.");
|
||||
|
||||
this.name = name;
|
||||
this.abi = abi;
|
||||
}
|
||||
|
||||
public string Name {
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public CppAbi Abi {
|
||||
get { return abi; }
|
||||
}
|
||||
|
||||
// For a class that may have fields with no virtual methods to be overridden
|
||||
public Iface GetClass<Iface,NativeLayout> (string className)
|
||||
where Iface : ICppInstantiatable
|
||||
where NativeLayout : struct
|
||||
{
|
||||
|
||||
return Abi.ImplementClass<Iface, NativeLayout> (interopModule, null, Name, className);
|
||||
}
|
||||
|
||||
// For a class that may have fields and virtual methods to be overridden
|
||||
public Iface GetClass<Iface,NativeLayout,Managed> (string className)
|
||||
where Iface : ICppOverridable<Managed>
|
||||
where NativeLayout : struct
|
||||
where Managed : ICppInstance
|
||||
{
|
||||
|
||||
return Abi.ImplementClass<Iface, NativeLayout> (interopModule, typeof (Managed), Name, className);
|
||||
}
|
||||
// TODO: Define a method for pure virtual classes (no NativeLayout)?
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// Mono.VisualC.Interop.Interfaces.cs
|
||||
//
|
||||
// Author:
|
||||
// Alexander Corrado (alexander.corrado@gmail.com)
|
||||
//
|
||||
// Copyright (C) 2010 Alexander Corrado
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
namespace Mono.VisualC.Interop
|
||||
{
|
||||
|
||||
public interface ICppInstance : IDisposable
|
||||
{
|
||||
IntPtr Native { get; }
|
||||
}
|
||||
|
||||
public interface ICppInstantiatable
|
||||
{
|
||||
CppInstancePtr Alloc();
|
||||
void Destruct(CppInstancePtr instance);
|
||||
}
|
||||
|
||||
public interface ICppOverridable<T> where T : ICppInstance
|
||||
{
|
||||
CppInstancePtr Alloc(T managed);
|
||||
void Destruct(CppInstancePtr instance);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?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>
|
||||
<ProjectGuid>{4A864586-93C5-4DC1-8A80-F094A88506D7}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<RootNamespace>Mono.VisualC.Interop</RootNamespace>
|
||||
</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>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>Mono.VisualC.Interop</AssemblyName>
|
||||
</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>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>CPPInterop</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Linux|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<AssemblyName>CPPInterop</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Mac|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Mac</OutputPath>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AssemblyName>Mono.VisualC.Interop</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CppLibrary.cs" />
|
||||
<Compile Include="AssemblyInfo.cs" />
|
||||
<Compile Include="ABI\CppAbi.cs" />
|
||||
<Compile Include="ABI\Impl\Itanium.cs" />
|
||||
<Compile Include="Interfaces.cs" />
|
||||
<Compile Include="ABI\VTableManaged.cs" />
|
||||
<Compile Include="Attributes.cs" />
|
||||
<Compile Include="CppInstancePtr.cs" />
|
||||
<Compile Include="CppField.cs" />
|
||||
<Compile Include="ABI\VTableCOM.cs" />
|
||||
<Compile Include="ABI\VTable.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<Compile Include="ABI\MethodType.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
<Folder Include="ABI\" />
|
||||
<Folder Include="ABI\Impl\" />
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<MonoDevelop>
|
||||
<Properties InternalTargetFrameworkVersion="3.5" />
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Mono.VisualC.Interop {
|
||||
public static class Util {
|
||||
|
||||
public static MethodInfo GetMethodInfoForDelegate (Type delType)
|
||||
{
|
||||
return delType.GetMethod ("Invoke");
|
||||
}
|
||||
|
||||
public static Type GetDelegateTypeForMethodInfo (ModuleBuilder mod, MethodInfo targetMethod)
|
||||
{
|
||||
|
||||
TypeAttributes typeAttr = TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass;
|
||||
TypeBuilder del = mod.DefineType (mod.Name + "_" + targetMethod.Name + "_VTdel", typeAttr, typeof(MulticastDelegate));
|
||||
|
||||
|
||||
MethodAttributes ctorAttr = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
|
||||
ConstructorBuilder ctor = del.DefineConstructor (ctorAttr, CallingConventions.Standard, new Type[] { typeof(object), typeof(System.IntPtr) });
|
||||
ctor.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
|
||||
|
||||
Type[] parameterTypes = GetMethodParameterTypes (targetMethod, true);
|
||||
MethodAttributes methodAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
|
||||
|
||||
MethodBuilder invokeMethod = del.DefineMethod ("Invoke", methodAttr, targetMethod.ReturnType, parameterTypes);
|
||||
invokeMethod.SetImplementationFlags (MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
|
||||
|
||||
return del.CreateType ();
|
||||
}
|
||||
|
||||
public static Delegate GetDelegateForMethodInfo (ModuleBuilder mod, MethodInfo targetMethod)
|
||||
{
|
||||
Type delType = GetDelegateTypeForMethodInfo (mod, targetMethod);
|
||||
return Delegate.CreateDelegate (delType, targetMethod);
|
||||
}
|
||||
|
||||
public static Type[] GetDelegateParameterTypes (Type delType)
|
||||
{
|
||||
MethodInfo invoke = GetMethodInfoForDelegate (delType);
|
||||
if (invoke == null)
|
||||
return null;
|
||||
|
||||
return GetMethodParameterTypes (invoke, false);
|
||||
}
|
||||
|
||||
public static Type[] GetMethodParameterTypes (MethodInfo method, bool forPInvoke)
|
||||
{
|
||||
ParameterInfo[] parameters = method.GetParameters ();
|
||||
Type[] parameterTypes = new Type [parameters.Length];
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++) {
|
||||
if (forPInvoke) {
|
||||
if (parameters [i].ParameterType.Equals (typeof (CppInstancePtr)))
|
||||
parameterTypes [i] = typeof (IntPtr);
|
||||
else if (parameters [i].ParameterType.IsPointer)
|
||||
parameterTypes [i] = parameters [i].ParameterType.GetElementType ().MakeByRefType ();
|
||||
else
|
||||
parameterTypes [i] = parameters [i].ParameterType;
|
||||
} else
|
||||
parameterTypes [i] = parameters [i].ParameterType;
|
||||
}
|
||||
|
||||
return parameterTypes;
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче