【发布时间】:2022-01-05 16:16:29
【问题描述】:
我目前正在尝试重建和更新一个用 Rust 编写的项目(更具体地说,它是 Skyrim 的 SKSE64 插件:https://github.com/lukasaldersley/sse-mod-skyrim-search-se 来自 qbx2) 我面临的最后一个问题是库现在需要从我们的库中导出一个结构以进行版本检查。
我尝试了许多可能很愚蠢的方法来实现它,但我无法让它发挥作用。
c++代码如下:
struct SKSEPluginVersionData
{
enum
{
kVersion = 1,
};
enum
{
// set this if you are using a (potential at this time of writing) post-AE version of the Address Library
kVersionIndependent_AddressLibraryPostAE = 1 << 0,
// set this if you exclusively use signature matching to find your addresses and have NO HARDCODED ADDRESSES
kVersionIndependent_Signatures = 1 << 1,
};
UInt32 dataVersion; // set to kVersion
UInt32 pluginVersion; // version number of your plugin
char name[256]; // null-terminated ASCII plugin name
char author[256]; // null-terminated ASCII plugin author name (can be empty)
char supportEmail[256]; // null-terminated ASCII support email address (can be empty)
// version compatibility
UInt32 versionIndependence; // set to one of the kVersionIndependent_ enums or zero
UInt32 compatibleVersions[16]; // zero-terminated list of RUNTIME_VERSION_ defines your plugin is compatible with
UInt32 seVersionRequired; // minimum version of the script extender required, compared against PACKED_SKSE_VERSION
// you probably should just set this to 0 unless you know what you are doing
};
#define RUNTIME_VERSION_1_6_318 0x010613E0
extern "C" {
__declspec(dllexport) SKSEPluginVersionData SKSEPlugin_Version =
{
SKSEPluginVersionData::kVersion,
1,
"Skyrim Search",
"qbx2",
"",
0, // not version independent
{ RUNTIME_VERSION_1_6_318, 0 }, // RUNTIME_VERSION_1_6_318 is
0, // works with any version of the script extender. you probably do not need to put anything here
};
};
到目前为止,我在 Rust 中的想法是:
enum KVersionenum {
KVersion=1,
}
#[repr(C)]
pub struct SKSEPluginVersionData {
dataVersion: u32,
pluginVersion: u32,
name: [char;256],
author: [char;256],
supportEmail: [char;256],
versionIndependence: u32,
compatibleVersions: [u32;16],
seVersionRequired: u32,
}
//0x010613E0 is RUNTIME_VERSION_1_6_318
//how can I do this OUTSIDE of a method and how can I make it public to the dll? is that even possible?
let SKSEPlugin_Version = SKSEPluginVersionData {
dataVersion: KVersionenum::KVersion as u32,
pluginVersion: 1,
name: "Skyrim Search\0", //this doesn't work, how can I fill this char array?
author: "qbx2 / lukasaldersley\0", //same here
supportEmail: "something@something.something\0", //and here
versionIndependence: 0,
compatibleVersions: [0x010613E0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], //I'm sure this is a horrible way of doing this
seVersionRequired: 0,
};
当我尝试在函数之外使用 let thingy 时,编译器抱怨期待“项目”,但我的 google-fu 不够好,无法在那里找到任何有用的信息,因为我一直在寻找有关视频游戏中项目的信息生锈。
对于汽车数组/字符串问题,我遇到了 std:ffi 的东西,完全迷失在它的文档中,但据我所知,它只会处理指针,这不是我需要的。
现在的两个问题是如何填充这些 char 数组(我不能只传递一个指针)以及如何创建这个结构的实例作为全局变量(或者 Rust 称之为),因为let name = something {...} 不起作用。
据我所知,导出到 dll 的函数看起来像这样,但我认为它不会以相同的方式用于该结构。
#[no_mangle]
pub extern "C" fn SKSEPlugin_Query(skse: *const SKSEInterface, info: *mut PluginInfo) -> bool {...}
甚至有可能做到这一点吗?
有人可以在这里帮助我,或者至少为我指明正确的方向吗? 请注意,我是 Rust 的绝对初学者,显然错误地认为仅添加一个结构不会那么复杂。
【问题讨论】:
-
AFAIK,Rust 中没有导出全局变量的语法。最好的办法可能是用 C 语言编写该变量,将其编译为目标文件并将其链接到 Rust DLL 的其余部分。
-
@rodrigo 这不起作用:Can a Rust constant/static be exposed to C?
-
@kmdreko: 嗯,很棘手……它声明了一个全局变量,但没有通过 dll 导出它。在 Windows 中,您需要
__declspec(export)符号。我似乎记得您也可以在 DEF 文件中执行此操作,用作链接器的输入,甚至作为链接器的 direct argument,但我已经有一段时间没有在 Windows 上进行黑客攻击了。