使用 Rust 的重启管理器解锁文件

问题描述 投票:0回答:1

我正在尝试使用

C++
板条箱将此函数从
Rust
转换为
windows

#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
并跟踪每个函数,我正在尝试拟合参数,但看起来我在这个过程中错过了一些重要的东西。

windows winapi rust windows-rs
1个回答
0
投票

在引发访问冲突之前,代码会打印出:

160 0x0

第一个数字 160 是

RmStartSession()
调用的返回值。这是由命名常量 ERROR_BAD_ARGUMENTS 标识的
系统错误代码
,可转换为错误文本“一个或多个参数不正确。”

防止访问冲突的第一步是观察

RmStartSession()
的返回值,如果它不是
ERROR_SUCCESS
则释放,如下所示:

let result = RmStartSession(
    psessionhandle,
    dwsessionflags,
    windows::core::PWSTR(strsessionkey),
);
if result != ERROR_SUCCESS.0 {
    return Err("Failed to start session".into());
}

解决了这个问题,我们就可以继续前进并找出哪些论点是错误的。必要的信息可从 Microsoft 详细介绍函数调用契约的文档中获得。

RmStartSession
的相关参数有:

pSessionHandle

指向重新启动管理器会话句柄的指针。

strSessionKey

null
结尾的字符串,其中包含新会话的会话密钥。 在调用
RmStartSession
函数之前必须分配字符串。

任一指针必须是有效并且引用调用者提供的内存。前者是指向

DWORD
(Rust 中的
u32
)的指针,而后者是指向长度为
WCHAR
u16
(Rust 中的
CCH_RM_SESSION_KEY + 1
)数组开头的指针。应用这些更改会生成以下代码:

fn release_file_lock(path: &str) -> Result<(), Box<dyn std::error::Error>> {
    let mut session_handle = 0_u32;
    let mut session_key = [0_u16; CCH_RM_SESSION_KEY as usize + 1];
    unsafe {
        let result = RmStartSession(&mut session_handle, 0, PWSTR(session_key.as_mut_ptr()));
        if result != ERROR_SUCCESS.0 {
            return Err("Failed to start session".into());
        }
        println!("{:?} {:?}", result, session_handle);
        RmEndSession(session_handle);
    };
    Ok(())
}
© www.soinside.com 2019 - 2024. All rights reserved.