我正在用 Rust 创建一个 Unity 原生插件。
由于我需要在 Rust 中接收 ID3D11Texture2D,所以我决定使用 windows-rs crate 版本 0.56.0。
统一代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
public class DesktopCapture : MonoBehaviour
{
[DllImport("texture2d_user", EntryPoint = "modify_texture")]
static extern void ModifyTexture(IntPtr texptr);
void Start()
{
var tex = Texture2D.normalTexture;
ModifyTexture(tex.GetNativeTexturePtr());
}
}
Rust 代码
use windows::core::IUnknown;
use windows::Win32::Graphics::Direct3D11::*;
#[no_mangle]
pub extern "C" fn modify_texture(texptr: *mut IUnknown) {
let texture: *mut ID3D11Texture2D = texptr.cast::<ID3D11Texture2D>();
let dimension: D3D11_RESOURCE_DIMENSION = unsafe { (*texture).GetType() };
()
}
虽然参数传递顺利,但在 ID3D11Texture2D 上调用 GetType 方法导致了 Segmentation Failure 错误。
我想知道如何解决这个问题。预先感谢您的帮助。
为了确定问题是由 Unity 还是 Rust 引起,我用 C++ 创建了一个本机插件,并用它来创建 ID3D11Texture2D。调用这些方法没有任何问题,所以我相信问题不在于 Unity。
Unity 编辑器日志
Received signal SIGSEGV
Obtained 26 stack frames
0x00007ffadcdc1020 (texture2d_user) texture2d_user::modify_texture (at C:/Users/sabro/source/testproject/texture2d_user/src/lib.rs:8)
0x000001ce154eb96a (Mono JIT Code) (wrapper managed-to-native) DesktopCapture:ModifyTexture (intptr)
0x000001ce154eb573 (Mono JIT Code) DesktopCapture:Start () (at C:/Users/sabro/source/testproject/DesktopCapture/Assets/DesktopCapture.cs:17)
0x000001cdef27a488 (Mono JIT Code) (wrapper runtime-invoke) object:runtime_invoke_void__this__ (object,intptr,intptr,intptr)
0x00007ffadf74e274 (mono-2.0-bdwgc) mono_jit_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/mini/mini-runtime.c:3445)
0x00007ffadf68eb74 (mono-2.0-bdwgc) do_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3066)
0x00007ffadf68ed0c (mono-2.0-bdwgc) mono_runtime_invoke (at C:/build/output/Unity-Technologies/mono/mono/metadata/object.c:3113)
0x00007ff78895a824 (Unity) scripting_method_invoke
0x00007ff788938944 (Unity) ScriptingInvocation::Invoke
0x00007ff78892715b (Unity) MonoBehaviour::InvokeMethodOrCoroutineChecked
0x00007ff788927266 (Unity) MonoBehaviour::InvokeMethodOrCoroutineChecked
0x00007ff7889212c2 (Unity) MonoBehaviour::DelayedStartCall
0x00007ff7883c2aa4 (Unity) DelayedCallManager::Update
0x00007ff7885f2c59 (Unity) `InitPlayerLoopCallbacks'::`2'::EarlyUpdateScriptRunDelayedStartupFrameRegistrator::Forward
0x00007ff7885d291c (Unity) ExecutePlayerLoop
0x00007ff7885d2a98 (Unity) ExecutePlayerLoop
0x00007ff7885d9375 (Unity) PlayerLoop
0x00007ff78959cd2f (Unity) PlayerLoopController::InternalUpdateScene
0x00007ff789594513 (Unity) PlayerLoopController::EnterPlayMode
0x00007ff7895a4887 (Unity) PlayerLoopController::SetIsPlaying
0x00007ff7895a7f50 (Unity) Application::TickTimer
0x00007ff789a1e51a (Unity) MainMessageLoop
0x00007ff789a23d80 (Unity) WinMain
0x00007ff78ae07fee (Unity) __scrt_common_main_seh
0x00007ffbd02e7344 (KERNEL32) BaseThreadInitThunk
0x00007ffbd04226b1 (ntdll) RtlUserThreadStart
看起来您的
.cast()
正在调用 <*mut T>::cast
而不是 <IUnknown as Interface>::cast
。前者只是一个直指针转换,而后者则经过QueryInterface
。赠品是 Interface::cast
返回 Result<T>
,但您的代码直接将结果分配给 *mut ID3D11Texture2D
变量。 Interface::cast
甚至没有资格被调用,因为它需要 &self
但你在原始指针上调用 .cast()
。
在
windows
箱中,像 IUnknown
这样的接口类型实际上已经是一个指针:我们在 C 或 C++ 中编写 IUnknown*
,而在 Rust 中只编写 IUnknown
。在通过 FFI 调用的 Rust 函数中,您的接口参数应输入 *mut c_void
,然后您可以使用 Interface::from_raw_borrowed
将它们转换为接口类型。
use std::ffi::c_void;
use windows::core::IUnknown;
use windows::Win32::Graphics::Direct3D11::*;
#[no_mangle]
pub extern "C" fn modify_texture(texptr: *mut c_void) {
let texptr = IUnknown::from_raw_borrowed(&texptr).expect("got a null texture pointer");
let texture: ID3D11Texture2D = texptr.cast::<ID3D11Texture2D>().expect("object doesn't implement ID3D11Texture2D");
let dimension: D3D11_RESOURCE_DIMENSION = unsafe { texture.GetType() };
}