mirror of
https://github.com/Sarsoo/csbindgen.git
synced 2024-12-22 22:46:26 +00:00
ReadMe 1.7.0
multi input_bindgen_file support bitflags crate support tuple struct support unit struct new csharp_disable_emit_dll_name option GroupedNativeMethods code generator
This commit is contained in:
parent
11c68c818d
commit
e4b25c3d73
@ -141,13 +141,19 @@ using System.Runtime.InteropServices;
|
||||
|
||||
static string ConvertMethodName(string typeName, string methodName, string removePrefix, string removeSuffix, bool removeUntilTypeName, bool fixMethodName)
|
||||
{
|
||||
if (!fixMethodName) return methodName;
|
||||
|
||||
if (removeUntilTypeName)
|
||||
{
|
||||
var match = methodName.IndexOf(typeName);
|
||||
if (match != -1)
|
||||
{
|
||||
methodName = methodName.Substring(match + typeName.Length);
|
||||
goto FINAL;
|
||||
var substringMethodName = methodName.Substring(match + typeName.Length);
|
||||
if (substringMethodName.Trim(' ', '_') != "")
|
||||
{
|
||||
methodName = substringMethodName;
|
||||
goto FINAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -163,18 +169,15 @@ using System.Runtime.InteropServices;
|
||||
methodName = Regex.Replace(methodName, $"{Regex.Escape(removeSuffix)}$", "");
|
||||
}
|
||||
|
||||
methodName = methodName.Trim('_');
|
||||
methodName = methodName.Trim('_', ' ');
|
||||
|
||||
if (fixMethodName)
|
||||
var split = methodName.Split('_');
|
||||
methodName = string.Concat(split.Select(x =>
|
||||
{
|
||||
var split = methodName.Split('_');
|
||||
methodName = string.Concat(split.Select(x =>
|
||||
{
|
||||
if (x.Length == 0) return x;
|
||||
if (x.Length == 1) return char.ToUpper(x[0]).ToString();
|
||||
return char.ToUpper(x[0]) + x.Substring(1);
|
||||
}));
|
||||
}
|
||||
if (x.Length == 0) return x;
|
||||
if (x.Length == 1) return char.ToUpper(x[0]).ToString();
|
||||
return char.ToUpper(x[0]) + x.Substring(1);
|
||||
}));
|
||||
|
||||
return methodName;
|
||||
}
|
||||
|
164
README.md
164
README.md
@ -26,7 +26,7 @@ Install on `Cargo.toml` as `build-dependencies` and set up `bindgen::Builder` on
|
||||
|
||||
```toml
|
||||
[build-dependencies]
|
||||
csbindgen = "1.6.0"
|
||||
csbindgen = "1.7.0"
|
||||
```
|
||||
|
||||
### Rust to C#.
|
||||
@ -163,6 +163,7 @@ csbindgen::Builder::default()
|
||||
.csharp_entry_point_prefix("") // optional, default: ""
|
||||
.csharp_method_prefix("") // optional, default: ""
|
||||
.csharp_use_function_pointer(true) // optional, default: true
|
||||
.csharp_disable_emit_dll_name(false) // optional, default: false
|
||||
.csharp_dll_name_if("UNITY_IOS && !UNITY_EDITOR", "__Internal") // optional, default: ""
|
||||
.generate_csharp_file("../dotnet-sandbox/NativeMethods.cs") // required
|
||||
.unwrap();
|
||||
@ -192,7 +193,9 @@ namespace {csharp_namespace}
|
||||
|
||||
`csharp_dll_name_if` is optional. If specified, `#if` allows two DllName to be specified, which is useful if the name must be `__Internal` at iOS build.
|
||||
|
||||
`input_extern_file` allows mulitple call, if you need to add dependent struct, use this.
|
||||
`csharp_disable_emit_dll_name` is optional, if set to true then don't emit `const string __DllName`. It is useful for generate same class-name from different builder.
|
||||
|
||||
`input_extern_file` and `input_bindgen_file` allow mulitple call, if you need to add dependent struct, use this.
|
||||
|
||||
```rust
|
||||
csbindgen::Builder::default()
|
||||
@ -341,6 +344,56 @@ internal static unsafe partial class NativeMethods
|
||||
|
||||
If Unity, configure Platform settings in each native library's inspector.
|
||||
|
||||
Grouping Extension Methods
|
||||
---
|
||||
In an object-oriented style, it is common to create methods that take a pointer to a state (this) as their first argument. With csbindgen, you can group these methods using extension methods by specifying a Source Generator on the C# side.
|
||||
|
||||
Install csbindgen from NuGet, and specify [GroupedNativeMethods] for the partial class of the generated extension methods.
|
||||
|
||||
> PM> Install-Package [csbindgen](https://www.nuget.org/packages/csbindgen)
|
||||
|
||||
```csharp
|
||||
// create new file and write same type-name with same namespace
|
||||
namespace CsBindgen
|
||||
{
|
||||
// append `GroupedNativeMethods` attribute
|
||||
[GroupedNativeMethods()]
|
||||
internal static unsafe partial class NativeMethods
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
// original methods
|
||||
[DllImport(__DllName, EntryPoint = "counter_context_insert", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void counter_context_insert(counter_context* context, int value);
|
||||
|
||||
// generated methods
|
||||
public static void Insert(this ref global::CsBindgen.counter_context @context, int @value)
|
||||
|
||||
// ----
|
||||
|
||||
counter_context* context = NativeMethods.create_counter_context();
|
||||
|
||||
// standard style
|
||||
NativeMethods.counter_context_insert(context, 10);
|
||||
|
||||
// generated style
|
||||
context->Insert(10);
|
||||
```
|
||||
|
||||
`GroupedNativeMethods` has four configuration parameters.
|
||||
|
||||
```csharp
|
||||
public GroupedNativeMethodsAttribute(
|
||||
string removePrefix = "",
|
||||
string removeSuffix = "",
|
||||
bool removeUntilTypeName = true,
|
||||
bool fixMethodName = true)
|
||||
```
|
||||
|
||||
`removeUntilTypeName` will remove until find type-name in method-name. For example `foo_counter_context_insert(countext_context* foo)` -> `Insert`. As a result, it is recommended to use a naming convention where the same type name is placed immediately before the verb.
|
||||
|
||||
Type Marshalling
|
||||
---
|
||||
@ -383,6 +436,7 @@ Rust types will map these C# types.
|
||||
| `#[repr(C)]Struct` | `[StructLayout(LayoutKind.Sequential)]Struct` |
|
||||
| `#[repr(C)]Union` | `[StructLayout(LayoutKind.Explicit)]Struct` |
|
||||
| `#[repr(u*/i*)]Enum` | `Enum` |
|
||||
| [bitflags!](https://crates.io/crates/bitflags) | `[Flags]Enum` |
|
||||
| `extern "C" fn` | `delegate* unmanaged[Cdecl]<>` or `Func<>/Action<>` |
|
||||
| `Option<extern "C" fn>` | `delegate* unmanaged[Cdecl]<>` or `Func<>/Action<>` |
|
||||
| `*mut T` | `T*` |
|
||||
@ -442,6 +496,62 @@ internal unsafe partial struct MyVector3
|
||||
}
|
||||
```
|
||||
|
||||
Also supports tuple struct, it will generate `Item*` fields in C#.
|
||||
|
||||
```
|
||||
#[repr(C)]
|
||||
pub struct MyIntVec3(i32, i32, i32);
|
||||
```
|
||||
|
||||
```csharp
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct MyIntVec3
|
||||
{
|
||||
public int Item1;
|
||||
public int Item2;
|
||||
public int Item3;
|
||||
}
|
||||
```
|
||||
|
||||
It also supports unit struct, but there is no C# struct that is synonymous with Rust's unit struct (0 byte), so it cannot be materialized. Instead of using void*, it is recommended to use typed pointers.
|
||||
|
||||
```
|
||||
// 0-byte
|
||||
#[repr(C)]
|
||||
pub struct CounterContext;
|
||||
```
|
||||
|
||||
```csharp
|
||||
// 1-byte
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct CounterContext
|
||||
{
|
||||
}
|
||||
```
|
||||
|
||||
```rust
|
||||
// recommend to use as pointer, in C#, holds CounterContext*
|
||||
#[no_mangle]
|
||||
pub extern "C" fn create_counter_context() -> *mut CounterContext {
|
||||
let ctx = Box::new(InternalCounterContext {
|
||||
set: HashSet::new(),
|
||||
});
|
||||
Box::into_raw(ctx) as *mut CounterContext
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn counter_context_insert(context: *mut CounterContext, value: i32) {
|
||||
let mut counter = Box::from_raw(context as *mut InternalCounterContext);
|
||||
counter.set.insert(value);
|
||||
Box::into_raw(counter);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn destroy_counter_context(context: *mut CounterContext) {
|
||||
_ = Box::from_raw(context as *mut InternalCounterContext);
|
||||
}
|
||||
```
|
||||
|
||||
### Union
|
||||
|
||||
`Union` will generate `[FieldOffset(0)]` struct.
|
||||
@ -492,6 +602,34 @@ internal enum ByteTest : byte
|
||||
}
|
||||
```
|
||||
|
||||
### bitflags Enum
|
||||
|
||||
csbindgen supports [bitflags](https://crates.io/crates/bitflags) crate.
|
||||
|
||||
```rust
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
struct EnumFlags: u32 {
|
||||
const A = 0b00000001;
|
||||
const B = 0b00000010;
|
||||
const C = 0b00000100;
|
||||
const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
[Flags]
|
||||
internal enum EnumFlags : uint
|
||||
{
|
||||
A = 0b00000001,
|
||||
B = 0b00000010,
|
||||
C = 0b00000100,
|
||||
ABC = A | B | C,
|
||||
}
|
||||
```
|
||||
|
||||
### Function
|
||||
|
||||
You can receive, return function to/from C#.
|
||||
@ -591,40 +729,42 @@ NativeMethods.delete_context(context);
|
||||
|
||||
You can also pass memory allocated by C# to Rust (use `fixed` or `GCHandle.Alloc(Pinned)`). The important thing is that memory allocated in Rust must release in Rust and memory allocated in C# must release in C#.
|
||||
|
||||
If you want to pass a non FFI Safe struct, cast it to `*mut c_void`. Then C# will treat it as a `void*`. csbindgen does not support Opaque Type.
|
||||
If you want to pass a non FFI Safe struct, cast it to `*mut c_void`. Then C# will treat it as a `void*`. csbindgen does not support Opaque Type. Additionally, by returning a unit struct instead of `c_void`, you can create a typed handler.
|
||||
|
||||
```rust
|
||||
#[no_mangle]
|
||||
pub extern "C" fn create_counter_context() -> *mut c_void {
|
||||
let ctx = Box::new(CounterContext {
|
||||
pub extern "C" fn create_counter_context() -> *mut CounterContext {
|
||||
let ctx = Box::new(InternalCounterContext {
|
||||
set: HashSet::new(),
|
||||
});
|
||||
Box::into_raw(ctx) as *mut c_void
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn insert_counter_context(context: *mut c_void, value: i32) {
|
||||
let mut counter = Box::from_raw(context as *mut CounterContext);
|
||||
pub unsafe extern "C" fn insert_counter_context(context: *mut CounterContext, value: i32) {
|
||||
let mut counter = Box::from_raw(context as *mut InternalCounterContext);
|
||||
counter.set.insert(value);
|
||||
Box::into_raw(counter);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn delete_counter_context(context: *mut c_void) {
|
||||
let counter = Box::from_raw(context as *mut CounterContext);
|
||||
pub unsafe extern "C" fn delete_counter_context(context: *mut CounterContext) {
|
||||
let counter = Box::from_raw(context as *mut InternalCounterContext);
|
||||
for value in counter.set.iter() {
|
||||
println!("counter value: {}", value)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CounterContext {
|
||||
pub struct CounterContext;
|
||||
|
||||
// no repr(C)
|
||||
pub struct InternalCounterContext {
|
||||
pub set: HashSet<i32>,
|
||||
}
|
||||
```
|
||||
|
||||
```csharp
|
||||
// in C#, ctx = void*
|
||||
var ctx = NativeMethods.create_counter_context();
|
||||
|
||||
NativeMethods.insert_counter_context(ctx, 10);
|
||||
@ -633,6 +773,8 @@ NativeMethods.insert_counter_context(ctx, 20);
|
||||
NativeMethods.delete_counter_context(ctx);
|
||||
```
|
||||
|
||||
In this case, recommed to use with [Grouping Extension Methods](#grouping-extension-methods).
|
||||
|
||||
If you want to pass null-pointer, in rust side, convert to Option by `as_ref()`.
|
||||
|
||||
```rust
|
||||
|
1
csbindgen-tests/Cargo.toml
vendored
1
csbindgen-tests/Cargo.toml
vendored
@ -14,6 +14,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
csbindgen = { path = "../csbindgen" }
|
||||
bitflags = "2.1.0"
|
||||
# physx-sys = "0.11.0"
|
||||
|
||||
[build-dependencies]
|
||||
|
1
csbindgen-tests/build.rs
vendored
1
csbindgen-tests/build.rs
vendored
@ -65,7 +65,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
.generate_to_file("src/lz4_ffi.rs", "../dotnet-sandbox/lz4_bindgen.cs")
|
||||
.unwrap();
|
||||
|
||||
|
||||
// csbindgen::Builder::default()
|
||||
// .input_bindgen_file("src/sqlite3.rs")
|
||||
// .method_filter(|x| x.starts_with("sqlite3_"))
|
||||
|
72
csbindgen-tests/src/lib.rs
vendored
72
csbindgen-tests/src/lib.rs
vendored
@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
ffi::{c_char, c_long, c_ulong, c_void, CString},
|
||||
ffi::{c_char, c_long, c_ulong, CString},
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -66,8 +66,6 @@ mod lz4_ffi;
|
||||
// println!("{:?}", hoge);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// #[no_mangle]
|
||||
// pub extern "C" fn string_char(str: char) {
|
||||
// println!("{}", str);
|
||||
@ -100,17 +98,26 @@ pub struct JPH_ContactManifold {
|
||||
pub extern "C" fn JPH_PruneContactPoints(
|
||||
ioContactPointsOn1: *mut JPH_ContactPoints,
|
||||
ioContactPointsOn2: *mut JPH_ContactManifold,
|
||||
)
|
||||
{
|
||||
) {
|
||||
todo!();
|
||||
}
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
struct EnumFlags: u32 {
|
||||
const A = 0b00000001;
|
||||
const B = 0b00000010;
|
||||
const C = 0b00000100;
|
||||
const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
|
||||
}
|
||||
}
|
||||
|
||||
/// my comment!
|
||||
#[no_mangle]
|
||||
pub extern "C" fn comment_one() {
|
||||
}
|
||||
|
||||
extern "C" fn comment_one(_flags: EnumFlags) {}
|
||||
|
||||
/// Multiline Comments
|
||||
/// # GOTO
|
||||
@ -121,22 +128,16 @@ pub extern "C" fn comment_one() {
|
||||
/// TO
|
||||
///
|
||||
/// ZZZ
|
||||
pub extern "C" fn long_jpn_comment() {
|
||||
}
|
||||
|
||||
|
||||
pub extern "C" fn long_jpn_comment() {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct my_int_vec3(i32,i32,i32);
|
||||
|
||||
pub extern "C" fn use_vec3(_v3: my_int_vec3) {
|
||||
|
||||
}
|
||||
pub struct my_int_vec3(i32, i32, i32);
|
||||
|
||||
pub extern "C" fn use_vec3(_v3: my_int_vec3) {}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct NfcCard {
|
||||
pub delegate: unsafe extern "C" fn(ByteArray) -> ByteArray
|
||||
pub delegate: unsafe extern "C" fn(ByteArray) -> ByteArray,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -150,11 +151,11 @@ pub struct ByteArray {
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct event {
|
||||
pub a: i32
|
||||
pub a: i32,
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn event(event: event ) {
|
||||
pub extern "C" fn event(event: event) {
|
||||
println!("{:?}", event);
|
||||
}
|
||||
|
||||
@ -283,27 +284,30 @@ pub extern "C" fn my_add(x: i32, y: i32) -> i32 {
|
||||
x + y
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CounterContext;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn create_counter_context() -> *mut c_void {
|
||||
let ctx = Box::new(CounterContext {
|
||||
pub extern "C" fn create_counter_context() -> *mut CounterContext {
|
||||
let ctx = Box::new(InternalCounterContext {
|
||||
set: HashSet::new(),
|
||||
});
|
||||
Box::into_raw(ctx) as *mut c_void
|
||||
Box::into_raw(ctx) as *mut CounterContext
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn insert_counter_context(context: *mut c_void, value: i32) {
|
||||
let mut counter = Box::from_raw(context as *mut CounterContext);
|
||||
pub unsafe extern "C" fn counter_context_insert(context: *mut CounterContext, value: i32) {
|
||||
let mut counter = Box::from_raw(context as *mut InternalCounterContext);
|
||||
counter.set.insert(value);
|
||||
Box::into_raw(counter);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn delete_counter_context(context: *mut c_void) {
|
||||
let counter = Box::from_raw(context as *mut CounterContext);
|
||||
for value in counter.set.iter() {
|
||||
println!("counter value: {}", value)
|
||||
}
|
||||
pub unsafe extern "C" fn destroy_counter_context(context: *mut CounterContext) {
|
||||
_ = Box::from_raw(context as *mut InternalCounterContext);
|
||||
// for value in counter.set.iter() {
|
||||
// println!("counter value: {}", value)
|
||||
// }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -329,8 +333,8 @@ pub struct MyVector3 {
|
||||
pub z: f32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct CounterContext {
|
||||
// not repr(C)
|
||||
pub struct InternalCounterContext {
|
||||
pub set: HashSet<i32>,
|
||||
}
|
||||
|
||||
@ -472,7 +476,6 @@ fn build_test() {
|
||||
// .generate_csharp_file("dotnet-sandbox/NativeMethods.cs")
|
||||
// .unwrap();
|
||||
|
||||
|
||||
csbindgen::Builder::new()
|
||||
.input_bindgen_file("csbindgen-tests/src/physx/physx_generated.rs")
|
||||
.input_bindgen_file("csbindgen-tests/src/physx/x86_64-pc-windows-msvc/structgen.rs")
|
||||
@ -567,7 +570,6 @@ pub struct CallbackTable {
|
||||
pub foobar: extern "C" fn(i: i32) -> i32,
|
||||
}
|
||||
|
||||
|
||||
// fn run_physix(){
|
||||
// unsafe {
|
||||
// let foundation = physx_create_foundation();
|
||||
@ -580,8 +582,6 @@ pub struct CallbackTable {
|
||||
// z: 0.0,
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// let dispatcher = phys_PxDefaultCpuDispatcherCreate(
|
||||
// 1,
|
||||
// null_mut(),
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{alias_map::AliasMap, builder::BindgenOptions, field_map::FieldMap, type_meta::*};
|
||||
use regex::Regex;
|
||||
use std::{collections::HashSet};
|
||||
use std::collections::HashSet;
|
||||
use syn::{ForeignItem, Item, Pat, ReturnType};
|
||||
|
||||
enum FnItem {
|
||||
@ -164,6 +164,14 @@ pub fn collect_struct(ast: &syn::File, result: &mut Vec<RustStruct>) {
|
||||
fields,
|
||||
is_union: false,
|
||||
});
|
||||
} else if let syn::Fields::Unit = &t.fields {
|
||||
let struct_name = t.ident.to_string();
|
||||
let fields: Vec<FieldMember> = Vec::new();
|
||||
result.push(RustStruct {
|
||||
struct_name,
|
||||
fields,
|
||||
is_union: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,7 +257,7 @@ pub fn collect_enum(ast: &syn::File, result: &mut Vec<RustEnum>) {
|
||||
|
||||
let token_string = t.mac.tokens.to_string();
|
||||
|
||||
let match1 = Regex::new("pub struct ([^ ]+) : ([^ ]+)")
|
||||
let match1 = Regex::new("struct ([^ ]+) : ([^ ]+)")
|
||||
.unwrap()
|
||||
.captures(token_string.as_str())
|
||||
.unwrap();
|
||||
@ -269,6 +277,7 @@ pub fn collect_enum(ast: &syn::File, result: &mut Vec<RustEnum>) {
|
||||
.as_str()
|
||||
.to_string()
|
||||
.replace("Self :: ", "")
|
||||
.replace(" . bits ()", "")
|
||||
.replace(" . bits", "")
|
||||
.trim()
|
||||
.to_string(),
|
||||
|
26
dotnet-sandbox/NativeMethods.cs
vendored
26
dotnet-sandbox/NativeMethods.cs
vendored
@ -18,7 +18,7 @@ namespace CsBindgen
|
||||
|
||||
/// <summary>my comment!</summary>
|
||||
[DllImport(__DllName, EntryPoint = "comment_one", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void comment_one();
|
||||
public static extern void comment_one(EnumFlags _flags);
|
||||
|
||||
/// <summary>Multiline Comments # GOTO Here Foo Bar TO ZZZ</summary>
|
||||
[DllImport(__DllName, EntryPoint = "long_jpn_comment", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
@ -91,13 +91,13 @@ namespace CsBindgen
|
||||
public static extern int my_add(int x, int y);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "create_counter_context", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void* create_counter_context();
|
||||
public static extern counter_context* create_counter_context();
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "insert_counter_context", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void insert_counter_context(void* context, int value);
|
||||
[DllImport(__DllName, EntryPoint = "counter_context_insert", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void counter_context_insert(counter_context* context, int value);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "delete_counter_context", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void delete_counter_context(void* context);
|
||||
[DllImport(__DllName, EntryPoint = "destroy_counter_context", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void destroy_counter_context(counter_context* context);
|
||||
|
||||
[DllImport(__DllName, EntryPoint = "pass_vector3", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||
public static extern void pass_vector3(MyVector3 v3);
|
||||
@ -186,6 +186,11 @@ namespace CsBindgen
|
||||
public int a;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal unsafe partial struct counter_context
|
||||
{
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal unsafe partial struct MyUnion
|
||||
{
|
||||
@ -225,6 +230,15 @@ namespace CsBindgen
|
||||
}
|
||||
|
||||
|
||||
[Flags]
|
||||
internal enum EnumFlags : uint
|
||||
{
|
||||
A = 0b00000001,
|
||||
B = 0b00000010,
|
||||
C = 0b00000100,
|
||||
ABC = A | B | C,
|
||||
}
|
||||
|
||||
internal enum IntEnumTest : sbyte
|
||||
{
|
||||
A = 1,
|
||||
|
14
dotnet-sandbox/Program.cs
vendored
14
dotnet-sandbox/Program.cs
vendored
@ -23,8 +23,18 @@ unsafe
|
||||
|
||||
|
||||
|
||||
var ctx = NativeMethods.create_context();
|
||||
ctx->DeleteContext2();
|
||||
var handler = NativeMethods.create_counter_context();
|
||||
|
||||
handler->Insert(10);
|
||||
handler->Insert(20);
|
||||
handler->Insert(30);
|
||||
|
||||
NativeMethods.destroy_counter_context(handler);
|
||||
|
||||
|
||||
|
||||
|
||||
//ctx->DeleteContext2();
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user