Skip to content

Commit 15ecd66

Browse files
authored
fix(win7): restore Windows 7 compatibility (#2)
1 parent 9a1cc71 commit 15ecd66

3 files changed

Lines changed: 58 additions & 51 deletions

File tree

.github/workflows/build.yml

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
target: x86_64-pc-windows-msvc
2525
artifact: sysproxy.win32-x64-msvc-win7.node
2626
features: ""
27-
toolchain: 1.70.0
27+
toolchain: 1.77.0
2828
- os: windows-latest
2929
target: aarch64-pc-windows-msvc
3030
artifact: sysproxy.win32-arm64-msvc.node
@@ -39,7 +39,7 @@ jobs:
3939
target: i686-pc-windows-msvc
4040
artifact: sysproxy.win32-ia32-msvc-win7.node
4141
features: ""
42-
toolchain: 1.70.0
42+
toolchain: 1.77.0
4343
# macOS
4444
- os: macos-latest
4545
target: x86_64-apple-darwin
@@ -75,6 +75,13 @@ jobs:
7575
- name: Install Dependencies
7676
run: pnpm install
7777

78+
- name: Pin deps for Rust 1.77 (Win7)
79+
if: contains(matrix.artifact, 'win7')
80+
run: |
81+
cargo update unicode-segmentation --precise 1.10.1
82+
cargo update clap --precise 4.5.37
83+
shell: bash
84+
7885
- name: Build
7986
run: |
8087
if [ -n "${{ matrix.features }}" ]; then

Cargo.toml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ tokio = { version = "1", features = [
2222
"macros",
2323
"time",
2424
], optional = true }
25-
napi = { version = "3", default-features = false, features = ["napi4"], optional = true }
26-
napi-derive = { version = "3", optional = true }
25+
napi = { version = "2", default-features = false, features = ["napi4"], optional = true }
26+
napi-derive = { version = "2", optional = true }
2727

2828
[target.'cfg(not(target_os = "macos"))'.dependencies]
29-
url = "2.5"
29+
url = ">=2.4, <2.5"
3030

3131
[target.'cfg(target_os = "linux")'.dependencies]
3232
xdg = "3.0"
@@ -36,19 +36,18 @@ system-configuration = "0.7"
3636

3737
[target.'cfg(target_os = "windows")'.dependencies]
3838
winreg = { version = "0.55", features = ["transactions"] }
39-
windows = { version = "0.62", features = [
39+
windows = { version = "0.58", features = [
4040
"Win32_Networking_WinInet",
4141
"Win32_NetworkManagement_Rras",
4242
"Win32_Foundation",
43-
"Win32_System_Memory",
4443
] }
4544

4645
[dev-dependencies]
4746
serial_test = "3.1"
48-
criterion = "0.7"
47+
criterion = "0.5"
4948

5049
[build-dependencies]
51-
napi-build = { version = "2", optional = true }
50+
napi-build = { version = "=2.1.0", optional = true }
5251

5352
[[bench]]
5453
name = "macos_behavior"

src/windows.rs

Lines changed: 43 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use windows::{
1111
INTERNET_PER_CONN_PROXY_BYPASS, INTERNET_PER_CONN_PROXY_SERVER, InternetSetOptionW,
1212
PROXY_TYPE_AUTO_DETECT, PROXY_TYPE_AUTO_PROXY_URL, PROXY_TYPE_DIRECT, PROXY_TYPE_PROXY,
1313
},
14-
System::Memory::{GetProcessHeap, HEAP_NONE, HEAP_ZERO_MEMORY, HeapAlloc, HeapFree},
1514
},
1615
core::{PCWSTR, PWSTR},
1716
};
@@ -307,51 +306,53 @@ fn get_ras_connections() -> Result<Vec<String>> {
307306
);
308307

309308
log::debug!("get allocate buffer size result code: {result_code}");
310-
if result_code == ERROR_BUFFER_TOO_SMALL {
311-
// Allocate the memory needed for the array of RAS entry names.
312-
let buffer_ptr = HeapAlloc(GetProcessHeap()?, HEAP_ZERO_MEMORY, buffer_size as usize);
313-
if buffer_ptr.is_null() {
314-
log::error!("HeapAlloc failed!");
315-
return Ok(connections);
316-
}
317-
let lp_ras_entry_name = buffer_ptr as *mut RASENTRYNAMEW;
318-
// The first RASENTRYNAME structure in the array must contain the structure size
319-
(*lp_ras_entry_name).dwSize = std::mem::size_of::<RASENTRYNAMEW>() as u32;
320-
321-
// 获取所有 RAS 列表
322-
let result_code = RasEnumEntriesW(
323-
PCWSTR::null(),
324-
PCWSTR::null(),
325-
Some(lp_ras_entry_name),
326-
&mut buffer_size,
327-
&mut entry_count,
328-
);
329-
// 如果函数成功,则返回值 ERROR_SUCCESS, 但是该 API 返回 u32, 参照对比 ERROR_SUCCESS 后,该值应该为 0
330-
log::debug!("get RAS entries result code: {result_code}");
331-
if result_code == 0 && entry_count > 0 {
332-
for i in 0..entry_count as isize {
333-
let entry = &*lp_ras_entry_name.offset(i);
334-
let name_arr = entry.szEntryName;
335-
// 去除宽字符多余的 0,以便更好的打印 RAS 名称
336-
let len = name_arr.iter().position(|&x| x == 0).unwrap_or(0);
337-
let name = String::from_utf16_lossy(&name_arr[..len]);
338-
connections.push(name);
339-
}
340-
log::debug!(
341-
"找到 {} 个拨号连接/VPN, {:?}",
342-
connections.len(),
343-
connections
344-
);
309+
310+
if result_code != ERROR_BUFFER_TOO_SMALL {
311+
if entry_count >= 1 {
312+
log::error!("The operation failed to acquire the buffer size");
313+
} else {
314+
log::debug!("There were no RAS entry names found");
345315
}
346-
// Deallocate memory for the connection buffer
347-
HeapFree(GetProcessHeap()?, HEAP_NONE, Some(buffer_ptr))?;
348316
return Ok(connections);
349317
}
350318

351-
if entry_count >= 1 {
352-
log::error!("The operation failed to acquire the buffer size");
353-
} else {
354-
log::debug!("There were no RAS entry names found");
319+
let entry_capacity = buffer_size as usize / std::mem::size_of::<RASENTRYNAMEW>();
320+
if entry_capacity == 0 {
321+
return Ok(connections);
322+
}
323+
324+
// 使用 Vec 管理缓冲区内存,避免手动堆分配
325+
let mut entries: Vec<RASENTRYNAMEW> = Vec::with_capacity(entry_capacity);
326+
for _ in 0..entry_capacity {
327+
entries.push(std::mem::zeroed());
328+
}
329+
// The first RASENTRYNAME structure in the array must contain the structure size
330+
entries[0].dwSize = std::mem::size_of::<RASENTRYNAMEW>() as u32;
331+
332+
// 获取所有 RAS 列表
333+
let result_code = RasEnumEntriesW(
334+
PCWSTR::null(),
335+
PCWSTR::null(),
336+
Some(entries.as_mut_ptr()),
337+
&mut buffer_size,
338+
&mut entry_count,
339+
);
340+
// 如果函数成功,则返回值 ERROR_SUCCESS, 但是该 API 返回 u32, 参照对比 ERROR_SUCCESS 后,该值应该为 0
341+
log::debug!("get RAS entries result code: {result_code}");
342+
343+
if result_code == 0 && entry_count > 0 {
344+
for entry in entries.iter().take(entry_count as usize) {
345+
let name_arr = entry.szEntryName;
346+
// 去除宽字符多余的 0,以便更好的打印 RAS 名称
347+
let len = name_arr.iter().position(|&x| x == 0).unwrap_or(0);
348+
let name = String::from_utf16_lossy(&name_arr[..len]);
349+
connections.push(name);
350+
}
351+
log::debug!(
352+
"找到 {} 个拨号连接/VPN, {:?}",
353+
connections.len(),
354+
connections
355+
);
355356
}
356357
}
357358

0 commit comments

Comments
 (0)