I'm trying to convert this function from C++
to Rust
using the windows
crate:
#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;
}
I successfully imported the necessary functions for that, but as a starting point I tried simply to start the session and close it and I got error 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(())
}
I would like to know what the flow of converting the code should be.
Currently, I'm looking in docs.rs/windows
and follow every function and I'm trying to fit the parameters, but it looks like I missed something important in that process.
Thanks to your assistance, I was able to delve deeper and successfully created the whole function and it works.
use windows::{Win32::{System::RestartManager::{
RmStartSession,
RmRegisterResources,
RmEndSession,
RmGetList,
RmShutdown,
RmForceShutdown,
CCH_RM_SESSION_KEY,
RM_PROCESS_INFO
}, Foundation::{ERROR_SUCCESS, WIN32_ERROR, ERROR_MORE_DATA}}, core::{PWSTR, PCWSTR, w}};
unsafe fn release_file_lock(file_path: PCWSTR) -> bool {
let mut session: u32 = 0;
let mut session_key_buffer = [0_u16; (CCH_RM_SESSION_KEY as usize) + 1];
let session_key = PWSTR(session_key_buffer.as_mut_ptr());
let result = RmStartSession(&mut session, 0, session_key);
if WIN32_ERROR(result) == ERROR_SUCCESS {
let result = RmRegisterResources(
session,
Some(&[file_path]),
None,
None
);
if WIN32_ERROR(result) == ERROR_SUCCESS {
let mut pnprocinfoneeded: u32 = 0;
let mut rgaffectedapps: [RM_PROCESS_INFO; 1] = [RM_PROCESS_INFO{..Default::default()}];
let mut lpdwrebootreasons: u32 = 0;
let mut pnprocinfo: u32 = 0;
let result = RmGetList(session, &mut pnprocinfoneeded, &mut pnprocinfo, Some(rgaffectedapps.as_mut_ptr()), &mut lpdwrebootreasons);
if WIN32_ERROR(result) == ERROR_SUCCESS || WIN32_ERROR(result) == ERROR_MORE_DATA {
if pnprocinfoneeded > 0 {
// If current process does not have enough privileges to close one of
// the "offending" processes, you'll get ERROR_FAIL_NOACTION_REBOOT
let result = RmShutdown(session, RmForceShutdown.0 as u32, None);
if WIN32_ERROR(result) == ERROR_SUCCESS {
// success
RmEndSession(session);
return true;
}
} else {
// success
RmEndSession(session);
return true;
}
}
}
RmEndSession(session);
return false;
}
return false;
}