我尝试使用windows
crate将此函数从C++
转换为Rust
:
#include <iostream>
#include "windows.h"
#include <RestartManager.h>
#pragma comment(lib ,"Rstrtmgr.lib")
BOOL ReleaseFileLock(LPCTSTR pFilePath)
{
BOOL bResult = FALSE;
DWORD dwSession;
WCHAR szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 };
DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
if (dwError == ERROR_SUCCESS)
{
dwError = RmRegisterResources(dwSession, 1, &pFilePath,
0, NULL, 0, NULL);
if (dwError == ERROR_SUCCESS)
{
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
RM_PROCESS_INFO rgpi[1];
DWORD dwReason;
dwError = RmGetList(dwSession, &nProcInfoNeeded,
&nProcInfo, rgpi, &dwReason);
if (dwError == ERROR_SUCCESS ||
dwError == ERROR_MORE_DATA)
{
if (nProcInfoNeeded > 0)
{
//If current process does not have enough privileges to close one of
//the "offending" processes, you'll get ERROR_FAIL_NOACTION_REBOOT
dwError = RmShutdown(dwSession, RmForceShutdown, NULL);
if (dwError == ERROR_SUCCESS)
{
bResult = TRUE;
}
}
else
bResult = TRUE;
}
}
}
RmEndSession(dwSession);
SetLastError(dwError);
return bResult;
}
我成功地导入了必要的函数,但作为一个起点,我试图简单地启动会话并关闭它,我得到了错误STATUS_ACCESS_VIOLATION
:
use windows_sys::core::PWSTR;
use windows::Win32::System::RestartManager::{
RmStartSession,
RmEndSession,
RmRegisterResources,
RmGetList,
RmShutdown,
RmForceShutdown,
};
fn release_file_lock(path: &str) -> Result<(), Box<dyn std::error::Error>> {
let psessionhandle = std::ptr::null_mut();
let dwsessionflags: u32 = 0;
let strsessionkey = std::ptr::null_mut();
unsafe {
let result = RmStartSession(psessionhandle, dwsessionflags, windows::core::PWSTR(strsessionkey));
println!("{:?} {:?}", result, psessionhandle);
RmEndSession(*psessionhandle); // < --- STATUS_ACCESS_VIOLATION
};
Ok(())
}
我想知道转换代码的流程应该是什么。
目前,我正在docs.rs/windows
中查找并遵循每个函数,我试图拟合参数,但看起来我在这个过程中错过了一些重要的东西。
3条答案
按热度按时间jvlzgdj91#
在引发访问冲突之前,代码打印出:
第一个数字160是
RmStartSession()
调用的返回值。这是一个system error code,由命名常量ERROR_BAD_ARGUMENTS
标识,该常量转换为错误文本 “One or more arguments are not correct "。因此,防止访问冲突的第一步是观察
RmStartSession()
和bail的返回值,如果它不是ERROR_SUCCESS
,就像这样:解决了这个问题,我们就可以继续前进,找出哪些论点是错误的。必要的信息可以从Microsoft的文档中获得,该文档详细说明了函数调用合同。
RmStartSession
的相关参数为:pSessionHandle
:指向重新启动管理器会话句柄的指针。
strSessionKey
:一个以
null
结尾的字符串,包含新会话的会话密钥。调用RmStartSession
函数前必须先分配字符串。任何一个指针都必须是 * 有效 * 的,并且引用调用者提供的内存。前者是指向
DWORD
(Rust中为u32
)的指针,而后者是指向长度为CCH_RM_SESSION_KEY + 1
的WCHAR
s(Rust中为u16
s)数组的开始的指针。应用这些更改会导致以下代码:djp7away2#
我认为没有正确的方法将代码从一种语言转换为另一种语言。如果您不熟悉该语言,可以像在提供的rust片段中所做的那样逐层进行。通过这种方式,您可以在转换过程中更轻松地学习目标语言的概念。
在您的情况下,我建议每次只关注一个API调用,并检查结果是否与C源代码的结果匹配。让我分享一下我对转换主题的一些看法:
1.在第一次迭代中保持函数的一致性。例如,您的C代码具有函数签名
BOOL ReleaseFileLock(LPCTSTR pFilePath)
,但Rust具有release_file_lock(path: &str) -> Result<...>
。在unicode模式下,LPCTSTR
是指在windows中表示UTF 16编码的宽字符。Rust将字符串存储在UTF8中,但您稍后调用的API将使用UTF 16。一开始保持签名相同,可以确保您对函数行为的期望也是相同的。1.不要关心转换期间错误处理的细节。您已经从
Result<(), Box<dyn std::error::Error>>
开始,这意味着某种基本的错误转发。我通常会保持简单,暂时跳过错误处理部分。如果遇到返回Result<...>
的API函数,只需执行unwrap
。当然,由于unwrap
,这可能有句柄泄漏的副作用,但它只是在不熟悉的领域中更快地进行原型设计和转换代码。稍后在转换的终结过程中引入错误处理,逐步通过终止和资源管理来确保正确性。1.对类型、类型转换和内存概念要格外小心!你应该了解C和Rust的区别,并知道API期望从你传递的参数中得到什么。理解C代码中变量的意图和内容,然后研究如何使用Rust实现相同的目标。
让我们来看看转换过程,并探讨您在转换过程中犯的一些错误。下面的代码片段显示了基线的C++示例的精简版本。我做了一些小的类型修改,将
RmEndSession
移到了successful分支中。下面是向Rust的转换:
正如您所看到的,Rust解决方案的第一次迭代几乎与C解决方案相同。在Rust中有
DWORD
是u32
和WCHAR
是u16
的类型差异。需要额外的类型转换,如WIN32_ERROR(result)
和PWSTR(session_key_buffer.as_mut_ptr())
,将宽字符片转换为API调用所需的类型。但基本思想和变量内存布局是等价的。在你尝试转换的过程中,很多C代码的概念都被无意中遗漏了,或者被修改了,改变了变量的意图。在Rust版本中,您可以:
1.在对句柄执行某些操作之前,未检查API调用是否成功。为了避免在调试过程中产生垃圾数据,您应该始终检查返回值是否成功。
1.使用指针
let psessionhandle = std::ptr::null_mut()
,其中最初声明了值DWORD dwSession
。值和指针的混淆还导致了由于空指针的解引用而导致的访问冲突。在很多情况下,传递给C中的函数的可变引用(如&dwSession
)在Rust中转换为&mut dwSession
,或者对于复杂类型转换为.as_mut_ptr()
,所以你只需要记住C代码的原始想法。1.没有分配
WCHAR szSessionKey[]
作为API的缓冲区,而是传入了std::ptr::null_mut()
。API只需要一个指向内存的指针,它可以在其中存储这个会话密钥。在C中,这个指针来自分配给WCHAR szSessionKey[]
的堆栈,在函数调用过程中,你不必像&szSessionKey
那样引用它,因为在C中,指向堆栈分配内存块的变量已经是它的指针。在Rust中,你必须声明堆栈内存,然后专门将其指针与.as_mut_ptr()
传递给PWSTR(*mut u16)
,以实现等效的概念。有了这个建议,你应该能够转换整个代码。请记住,在第一次迭代之后,您可以返回并引入适当的错误处理,如果需要,您还可以将函数参数更新为更方便的类型,例如字符串切片而不是Windows特定类型。
3b6akqbq3#
感谢您的帮助,我能够深入研究,并成功地创建了整个功能,它工作。