Merge pull request #1014 from peterhuene/c-api-module-new
Change `wasm_module_new` to use `Module::from_binary`.
This commit is contained in:
@@ -831,7 +831,7 @@ pub unsafe extern "C" fn wasm_module_new(
|
|||||||
) -> *mut wasm_module_t {
|
) -> *mut wasm_module_t {
|
||||||
let binary = (*binary).as_slice();
|
let binary = (*binary).as_slice();
|
||||||
let store = &(*store).store.borrow();
|
let store = &(*store).store.borrow();
|
||||||
let module = match Module::from_binary_unchecked(store, binary) {
|
let module = match Module::from_binary(store, binary) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(_) => return ptr::null_mut(),
|
Err(_) => return ptr::null_mut(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,6 +20,17 @@ namespace Wasmtime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal Engine(Interop.WasmConfigHandle config)
|
||||||
|
{
|
||||||
|
Handle = Interop.wasm_engine_new_with_config(config);
|
||||||
|
config.SetHandleAsInvalid();
|
||||||
|
|
||||||
|
if (Handle.IsInvalid)
|
||||||
|
{
|
||||||
|
throw new WasmtimeException("Failed to create Wasmtime engine.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new Wasmtime <see cref="Store" />.
|
/// Creates a new Wasmtime <see cref="Store" />.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
254
crates/misc/dotnet/src/EngineBuilder.cs
Normal file
254
crates/misc/dotnet/src/EngineBuilder.cs
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Wasmtime
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Wasmtime compiler strategy.
|
||||||
|
/// </summary>
|
||||||
|
public enum CompilerStrategy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Automatically pick the compiler strategy.
|
||||||
|
/// </summary>
|
||||||
|
Auto,
|
||||||
|
/// <summary>
|
||||||
|
/// Use the Cranelift compiler.
|
||||||
|
/// </summary>
|
||||||
|
Cranelift,
|
||||||
|
/// <summary>
|
||||||
|
/// Use the Lightbeam compiler.
|
||||||
|
/// </summary>
|
||||||
|
Lightbeam
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the Wasmtime optimization level.
|
||||||
|
/// </summary>
|
||||||
|
public enum OptimizationLevel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Disable optimizations.
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
/// <summary>
|
||||||
|
/// Optimize for speed.
|
||||||
|
/// </summary>
|
||||||
|
Speed,
|
||||||
|
/// <summary>
|
||||||
|
/// Optimize for speed and size.
|
||||||
|
/// </summary>
|
||||||
|
SpeedAndSize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a builder of <see cref="Engine"/> instances.
|
||||||
|
/// </summary>
|
||||||
|
public class EngineBuilder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructs a new <see cref="EngineBuilder" />.
|
||||||
|
/// </summary>
|
||||||
|
public EngineBuilder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not to enable debug information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable debug information or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithDebugInfo(bool enable)
|
||||||
|
{
|
||||||
|
_enableDebugInfo = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not enable WebAssembly threads support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable WebAssembly threads support or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithWasmThreads(bool enable)
|
||||||
|
{
|
||||||
|
_enableWasmThreads = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not enable WebAssembly reference types support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable WebAssembly reference types support or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithReferenceTypes(bool enable)
|
||||||
|
{
|
||||||
|
_enableReferenceTypes = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not enable WebAssembly SIMD support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable WebAssembly SIMD support or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithSIMD(bool enable)
|
||||||
|
{
|
||||||
|
_enableSIMD = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not enable WebAssembly multi-value support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable WebAssembly multi-value support or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithMultiValue(bool enable)
|
||||||
|
{
|
||||||
|
_enableMultiValue = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not enable WebAssembly bulk memory support.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable WebAssembly bulk memory support or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithBulkMemory(bool enable)
|
||||||
|
{
|
||||||
|
_enableBulkMemory = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the compiler strategy to use.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="strategy">The compiler strategy to use.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithCompilerStrategy(CompilerStrategy strategy)
|
||||||
|
{
|
||||||
|
switch (strategy)
|
||||||
|
{
|
||||||
|
case CompilerStrategy.Auto:
|
||||||
|
_strategy = Interop.wasmtime_strategy_t.WASMTIME_STRATEGY_AUTO;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CompilerStrategy.Cranelift:
|
||||||
|
_strategy = Interop.wasmtime_strategy_t.WASMTIME_STRATEGY_CRANELIFT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CompilerStrategy.Lightbeam:
|
||||||
|
_strategy = Interop.wasmtime_strategy_t.WASMTIME_STRATEGY_LIGHTBEAM;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(strategy));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets whether or not enable the Cranelift debug verifier.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enable">True to enable the Cranelift debug verifier or false to disable.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithCraneliftDebugVerifier(bool enable)
|
||||||
|
{
|
||||||
|
_enableCraneliftDebugVerifier = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the optimization level to use.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">The optimization level to use.</param>
|
||||||
|
/// <returns>Returns the current builder.</returns>
|
||||||
|
public EngineBuilder WithOptimizationLevel(OptimizationLevel level)
|
||||||
|
{
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case OptimizationLevel.None:
|
||||||
|
_optLevel = Interop.wasmtime_opt_level_t.WASMTIME_OPT_LEVEL_NONE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OptimizationLevel.Speed:
|
||||||
|
_optLevel = Interop.wasmtime_opt_level_t.WASMTIME_OPT_LEVEL_SPEED;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OptimizationLevel.SpeedAndSize:
|
||||||
|
_optLevel = Interop.wasmtime_opt_level_t.WASMTIME_OPT_LEVEL_SPEED_AND_SIZE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(level));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the <see cref="Engine" /> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Returns the new <see cref="Engine" /> instance.</returns>
|
||||||
|
public Engine Build()
|
||||||
|
{
|
||||||
|
var config = Interop.wasm_config_new();
|
||||||
|
|
||||||
|
if (_enableDebugInfo.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_debug_info_set(config, _enableDebugInfo.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_enableWasmThreads.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_wasm_threads_set(config, _enableWasmThreads.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_enableReferenceTypes.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_wasm_reference_types_set(config, _enableReferenceTypes.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_enableSIMD.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_wasm_simd_set(config, _enableSIMD.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_enableBulkMemory.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_wasm_bulk_memory_set(config, _enableBulkMemory.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_enableMultiValue.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_wasm_multi_value_set(config, _enableMultiValue.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_strategy.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_strategy_set(config, _strategy.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_enableCraneliftDebugVerifier.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_cranelift_debug_verifier_set(config, _enableCraneliftDebugVerifier.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_optLevel.HasValue)
|
||||||
|
{
|
||||||
|
Interop.wasmtime_config_cranelift_opt_level_set(config, _optLevel.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Engine(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool? _enableDebugInfo;
|
||||||
|
private bool? _enableWasmThreads;
|
||||||
|
private bool? _enableReferenceTypes;
|
||||||
|
private bool? _enableSIMD;
|
||||||
|
private bool? _enableBulkMemory;
|
||||||
|
private bool? _enableMultiValue;
|
||||||
|
private Interop.wasmtime_strategy_t? _strategy;
|
||||||
|
private bool? _enableCraneliftDebugVerifier;
|
||||||
|
private Interop.wasmtime_opt_level_t? _optLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -180,6 +180,21 @@ namespace Wasmtime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class WasmConfigHandle : SafeHandle
|
||||||
|
{
|
||||||
|
public WasmConfigHandle() : base(IntPtr.Zero, true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsInvalid => handle == IntPtr.Zero;
|
||||||
|
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
Interop.wasm_config_delete(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class WasiConfigHandle : SafeHandle
|
internal class WasiConfigHandle : SafeHandle
|
||||||
{
|
{
|
||||||
public WasiConfigHandle() : base(IntPtr.Zero, true)
|
public WasiConfigHandle() : base(IntPtr.Zero, true)
|
||||||
@@ -277,6 +292,20 @@ namespace Wasmtime
|
|||||||
WASM_FUNCREF,
|
WASM_FUNCREF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal enum wasmtime_strategy_t : byte
|
||||||
|
{
|
||||||
|
WASMTIME_STRATEGY_AUTO,
|
||||||
|
WASMTIME_STRATEGY_CRANELIFT,
|
||||||
|
WASMTIME_STRATEGY_LIGHTBEAM
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum wasmtime_opt_level_t : byte
|
||||||
|
{
|
||||||
|
WASMTIME_OPT_LEVEL_NONE,
|
||||||
|
WASMTIME_OPT_LEVEL_SPEED,
|
||||||
|
WASMTIME_OPT_LEVEL_SPEED_AND_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
internal struct wasm_val_union_t
|
internal struct wasm_val_union_t
|
||||||
{
|
{
|
||||||
@@ -514,6 +543,9 @@ namespace Wasmtime
|
|||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
public static extern EngineHandle wasm_engine_new();
|
public static extern EngineHandle wasm_engine_new();
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern EngineHandle wasm_engine_new_with_config(WasmConfigHandle config);
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
public static extern void wasm_engine_delete(IntPtr engine);
|
public static extern void wasm_engine_delete(IntPtr engine);
|
||||||
|
|
||||||
@@ -826,8 +858,17 @@ namespace Wasmtime
|
|||||||
public static extern uint wasm_memory_size(MemoryHandle memory);
|
public static extern uint wasm_memory_size(MemoryHandle memory);
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
public static extern bool wasm_memory_grow(MemoryHandle memory, uint delta);
|
public static extern bool wasm_memory_grow(MemoryHandle memory, uint delta);
|
||||||
|
|
||||||
|
// Wasm config
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern WasmConfigHandle wasm_config_new();
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasm_config_delete(IntPtr config);
|
||||||
|
|
||||||
// WASI config
|
// WASI config
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
@@ -854,6 +895,7 @@ namespace Wasmtime
|
|||||||
public static extern void wasi_config_inherit_env(WasiConfigHandle config);
|
public static extern void wasi_config_inherit_env(WasiConfigHandle config);
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
public static extern bool wasi_config_set_stdin_file(
|
public static extern bool wasi_config_set_stdin_file(
|
||||||
WasiConfigHandle config,
|
WasiConfigHandle config,
|
||||||
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
|
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
|
||||||
@@ -863,6 +905,7 @@ namespace Wasmtime
|
|||||||
public static extern void wasi_config_inherit_stdin(WasiConfigHandle config);
|
public static extern void wasi_config_inherit_stdin(WasiConfigHandle config);
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
public static extern bool wasi_config_set_stdout_file(
|
public static extern bool wasi_config_set_stdout_file(
|
||||||
WasiConfigHandle config,
|
WasiConfigHandle config,
|
||||||
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
|
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
|
||||||
@@ -872,6 +915,7 @@ namespace Wasmtime
|
|||||||
public static extern void wasi_config_inherit_stdout(WasiConfigHandle config);
|
public static extern void wasi_config_inherit_stdout(WasiConfigHandle config);
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
public static extern bool wasi_config_set_stderr_file(
|
public static extern bool wasi_config_set_stderr_file(
|
||||||
WasiConfigHandle config,
|
WasiConfigHandle config,
|
||||||
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
|
[MarshalAs(UnmanagedType.LPUTF8Str)] string path
|
||||||
@@ -881,6 +925,7 @@ namespace Wasmtime
|
|||||||
public static extern void wasi_config_inherit_stderr(WasiConfigHandle config);
|
public static extern void wasi_config_inherit_stderr(WasiConfigHandle config);
|
||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
public static extern bool wasi_config_preopen_dir(
|
public static extern bool wasi_config_preopen_dir(
|
||||||
WasiConfigHandle config,
|
WasiConfigHandle config,
|
||||||
[MarshalAs(UnmanagedType.LPUTF8Str)] string path,
|
[MarshalAs(UnmanagedType.LPUTF8Str)] string path,
|
||||||
@@ -900,5 +945,34 @@ namespace Wasmtime
|
|||||||
|
|
||||||
[DllImport(LibraryName)]
|
[DllImport(LibraryName)]
|
||||||
public static extern IntPtr wasi_instance_bind_import(WasiInstanceHandle instance, IntPtr importType);
|
public static extern IntPtr wasi_instance_bind_import(WasiInstanceHandle instance, IntPtr importType);
|
||||||
}
|
|
||||||
|
// Wasmtime config
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_debug_info_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_wasm_threads_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_wasm_reference_types_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern IntPtr wasmtime_config_wasm_simd_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_wasm_bulk_memory_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_wasm_multi_value_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_strategy_set(WasmConfigHandle config, wasmtime_strategy_t strategy);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_cranelift_debug_verifier_set(WasmConfigHandle config, [MarshalAs(UnmanagedType.I1)] bool enable);
|
||||||
|
|
||||||
|
[DllImport(LibraryName)]
|
||||||
|
public static extern void wasmtime_config_cranelift_opt_level_set(WasmConfigHandle config, wasmtime_opt_level_t level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using System.Linq;
|
|||||||
namespace Wasmtime
|
namespace Wasmtime
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a build of WASI instances.
|
/// Represents a builder of <see cref="Wasi"/> instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WasiBuilder
|
public class WasiBuilder
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,10 @@ namespace Wasmtime.Tests
|
|||||||
{
|
{
|
||||||
public ModuleFixture()
|
public ModuleFixture()
|
||||||
{
|
{
|
||||||
Engine = new Engine();
|
Engine = new EngineBuilder()
|
||||||
|
.WithMultiValue(true)
|
||||||
|
.WithReferenceTypes(true)
|
||||||
|
.Build();
|
||||||
Store = Engine.CreateStore();
|
Store = Engine.CreateStore();
|
||||||
Module = Store.CreateModule(Path.Combine("Modules", ModuleFileName));
|
Module = Store.CreateModule(Path.Combine("Modules", ModuleFileName));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user