mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 22:11:48 +08:00
Compare commits
441 Commits
v1.78.1-de
...
20251007-v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f26d57f40 | ||
|
|
3bd2fe889a | ||
|
|
492a2629c2 | ||
|
|
b64ddf32ff | ||
|
|
e86a550985 | ||
|
|
fcccdacb99 | ||
|
|
487de4c29b | ||
|
|
d36c6cb067 | ||
|
|
a4b704252b | ||
|
|
93e8d26a75 | ||
|
|
0a3ecaac64 | ||
|
|
ea6b762021 | ||
|
|
265a43e31c | ||
|
|
6d156586ac | ||
|
|
68e3f607a3 | ||
|
|
0b240a3902 | ||
|
|
4082761606 | ||
|
|
e68c42ba64 | ||
|
|
347546ee0e | ||
|
|
ca717d6b80 | ||
|
|
5d623d80eb | ||
|
|
a2edbd9934 | ||
|
|
5830f39d50 | ||
|
|
0aa0b59635 | ||
|
|
3c6a485647 | ||
|
|
bbe1fa8416 | ||
|
|
ac4469bb4a | ||
|
|
9e61e8eafa | ||
|
|
b193199268 | ||
|
|
f8b7d37af1 | ||
|
|
b3e9202d72 | ||
|
|
0f819ade56 | ||
|
|
d682afcde2 | ||
|
|
e67754ee9f | ||
|
|
4897771fbf | ||
|
|
4128f3404a | ||
|
|
7bc25ceb38 | ||
|
|
f77f0f5e04 | ||
|
|
0e666efaad | ||
|
|
e2893b9516 | ||
|
|
fb86b13948 | ||
|
|
e22cc6921d | ||
|
|
42fdd91206 | ||
|
|
2329d95002 | ||
|
|
8dda6ba13f | ||
|
|
156e2b8056 | ||
|
|
aa48324b6d | ||
|
|
d2b05ef7c3 | ||
|
|
75545e60b3 | ||
|
|
b3d0b30b56 | ||
|
|
3ed3729fc2 | ||
|
|
cb7ba46be6 | ||
|
|
933b21598e | ||
|
|
7a8442d9ea | ||
|
|
c405186533 | ||
|
|
5d150115a8 | ||
|
|
26bc38cf8c | ||
|
|
8f769cdda3 | ||
|
|
6b35cd3aee | ||
|
|
4ae1281a3a | ||
|
|
9984d4bc8f | ||
|
|
c987ee9fd3 | ||
|
|
a031e6f5f7 | ||
|
|
da386c3119 | ||
|
|
bfd29fc0fc | ||
|
|
9617776be1 | ||
|
|
765f2abc40 | ||
|
|
519bc42e0a | ||
|
|
6537e6bce6 | ||
|
|
494aff1bd3 | ||
|
|
927527b888 | ||
|
|
08054e4873 | ||
|
|
a092fef575 | ||
|
|
2808b3d3da | ||
|
|
ef3b236d73 | ||
|
|
26f0365026 | ||
|
|
25ebfee6e2 | ||
|
|
c1ada03db1 | ||
|
|
0b17360346 | ||
|
|
da18b37a54 | ||
|
|
4cf040c01e | ||
|
|
95b77515dc | ||
|
|
65bbd8ca05 | ||
|
|
dbba954522 | ||
|
|
26d46be243 | ||
|
|
135f8290ec | ||
|
|
a8b4e1178d | ||
|
|
8bdf66ef02 | ||
|
|
5209b08709 | ||
|
|
933247dc2f | ||
|
|
4e43bf9d8f | ||
|
|
0f6a5816db | ||
|
|
8021678995 | ||
|
|
147b5edec4 | ||
|
|
2edbf3222e | ||
|
|
f6bf8c229c | ||
|
|
c30b90af44 | ||
|
|
3b72e7af3d | ||
|
|
37004647eb | ||
|
|
c85cb84e31 | ||
|
|
d504143d7e | ||
|
|
db1c7b9708 | ||
|
|
064cb34705 | ||
|
|
02c442ef99 | ||
|
|
e358cafb3f | ||
|
|
40e447bc05 | ||
|
|
f0bac9ee78 | ||
|
|
a75fbad0ea | ||
|
|
ae5a919421 | ||
|
|
749cb7578a | ||
|
|
622ea20819 | ||
|
|
a9374a5eb1 | ||
|
|
1b78b68e33 | ||
|
|
3e97fe0490 | ||
|
|
2bb34607cc | ||
|
|
fe7fca180e | ||
|
|
0a86b45d59 | ||
|
|
62e0dd365b | ||
|
|
b39c561b72 | ||
|
|
02d099629f | ||
|
|
0f55cd2395 | ||
|
|
119451e4f6 | ||
|
|
0f6d4e5760 | ||
|
|
452ed6a754 | ||
|
|
40928b8ab0 | ||
|
|
f1ed380b42 | ||
|
|
e28ae8f2ba | ||
|
|
d8c6d9d558 | ||
|
|
607123f0be | ||
|
|
0ff72ae665 | ||
|
|
552cee1c24 | ||
|
|
44f05a2968 | ||
|
|
244fbf56d1 | ||
|
|
24845039f1 | ||
|
|
2e5be847ce | ||
|
|
9e947f7a36 | ||
|
|
87a3c60330 | ||
|
|
0d460d543b | ||
|
|
eb535cad2c | ||
|
|
eff00033b0 | ||
|
|
b591f97297 | ||
|
|
9501bb4428 | ||
|
|
4e9757c743 | ||
|
|
8f35b2ef71 | ||
|
|
3782eeeaf1 | ||
|
|
ec78de7a74 | ||
|
|
bd1f311d09 | ||
|
|
31bf36db89 | ||
|
|
a96d344c22 | ||
|
|
dac4988514 | ||
|
|
a1f50f152c | ||
|
|
06a47f4a06 | ||
|
|
f7aa9f7b92 | ||
|
|
894b11704c | ||
|
|
5b1b6ddc73 | ||
|
|
baa5abab2e | ||
|
|
1b2ae29f4a | ||
|
|
99a2b968d5 | ||
|
|
029672a907 | ||
|
|
31ecbaa977 | ||
|
|
6580e1b6db | ||
|
|
16bbe4ccc0 | ||
|
|
6ea3642700 | ||
|
|
b8270d2264 | ||
|
|
7b7fe1b062 | ||
|
|
e67c97cc21 | ||
|
|
1033214658 | ||
|
|
55552ad118 | ||
|
|
552c53b15d | ||
|
|
278fc30ae8 | ||
|
|
80fb676763 | ||
|
|
c511fd1895 | ||
|
|
e43a644eb0 | ||
|
|
70c16caf6b | ||
|
|
21dcfc9435 | ||
|
|
56ff019185 | ||
|
|
44a6cb31aa | ||
|
|
a01ebdaa9d | ||
|
|
651b742cc2 | ||
|
|
e2b1eb6e4a | ||
|
|
2546620c8d | ||
|
|
826f75348c | ||
|
|
b27462da05 | ||
|
|
ad0ade5dd4 | ||
|
|
6e3cf4630e | ||
|
|
6f3768db4b | ||
|
|
98220ccf93 | ||
|
|
52688d7145 | ||
|
|
b24edae66b | ||
|
|
ac39ce26ee | ||
|
|
cf041c661b | ||
|
|
9d173d0bdc | ||
|
|
aafb608149 | ||
|
|
04dd125ee6 | ||
|
|
e501235b2e | ||
|
|
7c6a322787 | ||
|
|
eed729181b | ||
|
|
ce9d42d304 | ||
|
|
733e31e54b | ||
|
|
f1714f3228 | ||
|
|
44c90f0de4 | ||
|
|
8268310685 | ||
|
|
d64eaf6234 | ||
|
|
4d0b848676 | ||
|
|
d508ca33c8 | ||
|
|
86fdea129b | ||
|
|
79af98845a | ||
|
|
2c15c6b0ed | ||
|
|
52ee10efda | ||
|
|
2da7d02a2c | ||
|
|
7af4ba27f3 | ||
|
|
46cd974a58 | ||
|
|
3d791b7f78 | ||
|
|
29e27c1283 | ||
|
|
8434ab460c | ||
|
|
561d073bba | ||
|
|
d46d37acb9 | ||
|
|
4f4d841137 | ||
|
|
b7e80ceee9 | ||
|
|
8a3112c71f | ||
|
|
4276b1439b | ||
|
|
3f626149f4 | ||
|
|
30b674f8f5 | ||
|
|
fe3fb46e94 | ||
|
|
99c524c7b6 | ||
|
|
5da7a582bf | ||
|
|
229c46a0c1 | ||
|
|
78d347889b | ||
|
|
244741ba15 | ||
|
|
015fa601a3 | ||
|
|
1bd9e44ecb | ||
|
|
dc7cfdb762 | ||
|
|
36afbae5af | ||
|
|
89d56a10f0 | ||
|
|
8dcc6031e6 | ||
|
|
b524a5424a | ||
|
|
f06ad99658 | ||
|
|
f4ad61a41b | ||
|
|
3c948aca96 | ||
|
|
57ee792198 | ||
|
|
6d84364cec | ||
|
|
d74fc16cfd | ||
|
|
56d72cb30b | ||
|
|
2f6f03ce8f | ||
|
|
b437ff3dcc | ||
|
|
93d17c2c35 | ||
|
|
b70ea04f02 | ||
|
|
89cde8b518 | ||
|
|
8d78623730 | ||
|
|
4a5b05f669 | ||
|
|
c4f2b7ed2e | ||
|
|
e296c77b14 | ||
|
|
56611c6e41 | ||
|
|
1e216b8cb3 | ||
|
|
302700ac80 | ||
|
|
cc5d943a86 | ||
|
|
7942f93649 | ||
|
|
270c6dd64b | ||
|
|
9f1633bc63 | ||
|
|
8953ec0e1f | ||
|
|
8f5dd3bc93 | ||
|
|
97ee6e6ee0 | ||
|
|
ae626294f3 | ||
|
|
842a45aa17 | ||
|
|
686936e7b2 | ||
|
|
8ac8ad6ed9 | ||
|
|
e7eda49676 | ||
|
|
faae8c7a77 | ||
|
|
5cb67a6e09 | ||
|
|
06747dc38d | ||
|
|
c3813fd87b | ||
|
|
901584a2e4 | ||
|
|
f9e33c7fca | ||
|
|
ea36ca37f0 | ||
|
|
2ea06f3096 | ||
|
|
dc208973c8 | ||
|
|
18ddb1001b | ||
|
|
567bc4a112 | ||
|
|
c5dbf5a412 | ||
|
|
c084e66db5 | ||
|
|
bb6d35f91f | ||
|
|
ac59bc2999 | ||
|
|
7dfb1d395d | ||
|
|
46672ca976 | ||
|
|
94e7e23cda | ||
|
|
2fa0ca41d6 | ||
|
|
2ebe35c6d6 | ||
|
|
354066de0b | ||
|
|
3d3c1f8f23 | ||
|
|
24448d604d | ||
|
|
7d8e530ebf | ||
|
|
5db88040cc | ||
|
|
d9de6e78d7 | ||
|
|
da136bfebd | ||
|
|
6657063441 | ||
|
|
47e6d4d711 | ||
|
|
32c7bd2627 | ||
|
|
3422d064ac | ||
|
|
0b01d40a85 | ||
|
|
7f79dc6098 | ||
|
|
ac7590f23c | ||
|
|
998bd3a1a9 | ||
|
|
0f62f1d72c | ||
|
|
cb1b1a5cac | ||
|
|
63ccdd0a23 | ||
|
|
ead809cc90 | ||
|
|
dfd4851bf1 | ||
|
|
e50f11697f | ||
|
|
4800ad53dc | ||
|
|
9349c3f055 | ||
|
|
d7a82ae911 | ||
|
|
b3354fb033 | ||
|
|
9b56b11c9b | ||
|
|
15247c3637 | ||
|
|
4311d3b057 | ||
|
|
076db0637f | ||
|
|
8a7108910d | ||
|
|
be12600094 | ||
|
|
988305100d | ||
|
|
16ae28ee62 | ||
|
|
30aab57bc9 | ||
|
|
a573914668 | ||
|
|
83771cc2e6 | ||
|
|
d8eaba75d2 | ||
|
|
96f917a1ab | ||
|
|
44d81a6bdf | ||
|
|
1b0e8440ae | ||
|
|
e236dbe661 | ||
|
|
2ba7d09c21 | ||
|
|
2b937689bd | ||
|
|
eeb7eb7ad2 | ||
|
|
c8e29211eb | ||
|
|
57cce7ec22 | ||
|
|
78af721250 | ||
|
|
cba6c2dacc | ||
|
|
b4b12cdbdc | ||
|
|
e7c86c95fe | ||
|
|
f28d96e91a | ||
|
|
b25217dd38 | ||
|
|
f60da8665b | ||
|
|
3d8daff050 | ||
|
|
c41f3c21c1 | ||
|
|
8e7897bf76 | ||
|
|
050bf75fdd | ||
|
|
1bbfcd0a7c | ||
|
|
30106d0006 | ||
|
|
16974068d7 | ||
|
|
08d0f67062 | ||
|
|
2edcb5863c | ||
|
|
44b9e49a54 | ||
|
|
0175903f51 | ||
|
|
0ef282f89c | ||
|
|
b4eec7d44c | ||
|
|
2e040a39db | ||
|
|
7e0ee705ff | ||
|
|
361005e242 | ||
|
|
2ea26f7319 | ||
|
|
44c4ca232f | ||
|
|
f7bb45288e | ||
|
|
c99aa41744 | ||
|
|
4eb1cc939c | ||
|
|
d4c51f18f5 | ||
|
|
af89c8bba7 | ||
|
|
2e951ef0db | ||
|
|
80b82366c4 | ||
|
|
3d75eae9c0 | ||
|
|
0bd8d9c4ca | ||
|
|
b3c1132a25 | ||
|
|
bddcb16e8a | ||
|
|
3cb2ba6fa3 | ||
|
|
205c8914ed | ||
|
|
76e0b67599 | ||
|
|
2c617b230a | ||
|
|
72d3268d39 | ||
|
|
a093a77610 | ||
|
|
a9c6443c18 | ||
|
|
757932ed4a | ||
|
|
55aad85bdd | ||
|
|
952d87f858 | ||
|
|
81fbe68e3b | ||
|
|
c82cd15f24 | ||
|
|
9991f7015f | ||
|
|
e94fac0459 | ||
|
|
816833c9f3 | ||
|
|
a202d72cd6 | ||
|
|
0558b0621a | ||
|
|
6e12b398d4 | ||
|
|
cce9aa5e97 | ||
|
|
6020122297 | ||
|
|
bed11116fe | ||
|
|
66cf93ffdd | ||
|
|
8f1ca7dee2 | ||
|
|
b24eac52ae | ||
|
|
5aaa3a00b4 | ||
|
|
0d737228b0 | ||
|
|
f57c862c3c | ||
|
|
ba476533ed | ||
|
|
28b39688ec | ||
|
|
fd8b1a8807 | ||
|
|
bff44b5d74 | ||
|
|
a9ee32d020 | ||
|
|
4fd1864eef | ||
|
|
3775279659 | ||
|
|
5bba633ab1 | ||
|
|
900cc0afe3 | ||
|
|
29fa64825e | ||
|
|
1c59404299 | ||
|
|
563613be6b | ||
|
|
5ae2296400 | ||
|
|
9534ceccd9 | ||
|
|
878845941d | ||
|
|
a5be2bb5b5 | ||
|
|
19c954f972 | ||
|
|
576f9db387 | ||
|
|
28ff02f8cb | ||
|
|
d4a590d292 | ||
|
|
25f928fc8a | ||
|
|
5dd3d927d6 | ||
|
|
77950632f8 | ||
|
|
e85cee752d | ||
|
|
5c48f13a27 | ||
|
|
18b283db0a | ||
|
|
ca7888a537 | ||
|
|
246e90acd1 | ||
|
|
e58e33974a | ||
|
|
5cb07d003c | ||
|
|
3ecedc8fcf | ||
|
|
a88ed5d3a9 | ||
|
|
37fead2076 | ||
|
|
2770c761b2 | ||
|
|
4b28eb6758 | ||
|
|
ba45b44f45 | ||
|
|
f5186cbadd | ||
|
|
807924c51e | ||
|
|
155d849201 | ||
|
|
e9efd2705c | ||
|
|
204e0d041c | ||
|
|
227d75d956 | ||
|
|
d2706c8748 | ||
|
|
2518b8600f | ||
|
|
9300839d59 |
157
.github/workflows/Build_mR-NB.yml
vendored
Normal file
157
.github/workflows/Build_mR-NB.yml
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
name: Build_and_Release_mR-NB
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v1.78.2-dev
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_flag:
|
||||
description: 'Run NB release'
|
||||
required: false
|
||||
default: 'true'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
NB-Build-and-Release:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- runner: windows-latest
|
||||
platform: x64
|
||||
arch: x64
|
||||
- runner: windows-11-arm
|
||||
platform: ARM64
|
||||
arch: arm64
|
||||
runs-on: ${{ matrix.runner }}
|
||||
# Only run if:
|
||||
# - manual dispatch, OR
|
||||
# - push event AND commit message contains "NB release"
|
||||
if: >
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'push' && contains(github.event.head_commit.message, 'NB release'))
|
||||
|
||||
steps:
|
||||
- name: (01) Checkout Repository
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: (02) Setup MSBuild
|
||||
uses: microsoft/setup-msbuild@v2
|
||||
with:
|
||||
vs-version: '17.14.12'
|
||||
|
||||
- name: (03) Install and run dotnet-t4 to transform T4 templates
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet tool install --global dotnet-t4
|
||||
# Refresh PATH to include global tools
|
||||
$env:PATH += ";$env:USERPROFILE\.dotnet\tools"
|
||||
$ttFile = "$env:GITHUB_WORKSPACE\mRemoteNG\Properties\AssemblyInfo.tt"
|
||||
# VS Enterprise 2022 assemblies
|
||||
$vsPath = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\PublicAssemblies"
|
||||
Write-Host "Transforming T4 template"
|
||||
t4 $ttFile -P platformType=${{ matrix.platform }} -r:"$vsPath\EnvDTE.dll" -r:"$vsPath\Microsoft.VisualStudio.Interop.dll"
|
||||
env:
|
||||
PLATFORM: '${{ matrix.platform }}'
|
||||
|
||||
- name: (04) Cache NuGet Packages
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.nuget/packages
|
||||
key: ${{ runner.os }}-${{ matrix.arch }}-nuget-${{ hashFiles('**/*.csproj') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-${{ matrix.arch }}-nuget-
|
||||
|
||||
- name: (05) Restore NuGet Packages
|
||||
shell: pwsh
|
||||
run: dotnet restore
|
||||
|
||||
- name: (06) Build Release
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Release" -p:Platform=${{ matrix.platform }} /verbosity:minimal
|
||||
|
||||
- name: (07) Release Information
|
||||
id: version
|
||||
shell: pwsh
|
||||
run: |
|
||||
$assemblyInfoPath = "${{ github.workspace }}\mRemoteNG\Properties\AssemblyInfo.cs"
|
||||
$line = Get-Content $assemblyInfoPath | Where-Object { $_ -match 'AssemblyVersion\("(.+?)"\)' }
|
||||
if ($line -match 'AssemblyVersion\("(?<ver>\d+\.\d+\.\d+)\.(?<build>\d+)"\)') {
|
||||
$version = $matches['ver']
|
||||
$build = $matches['build']
|
||||
} else {
|
||||
throw "Could not extract version and build number"
|
||||
}
|
||||
$date = Get-Date -Format "yyyyMMdd"
|
||||
$zipName = "mRemoteNG-$date-v$version-NB-$build-${{ matrix.arch }}.zip"
|
||||
$tag = "$date-v$version-NB-($build)"
|
||||
$message = git log -1 --pretty=%B
|
||||
echo "message=$message" >> $env:GITHUB_OUTPUT
|
||||
echo "zipname=$zipName" >> $env:GITHUB_OUTPUT
|
||||
echo "version=$version" >> $env:GITHUB_OUTPUT
|
||||
echo "build=$build" >> $env:GITHUB_OUTPUT
|
||||
echo "tag=$tag" >> $env:GITHUB_OUTPUT
|
||||
$version = "${{ steps.version.outputs.version }}"
|
||||
|
||||
- name: (08) Extract Changelog Section
|
||||
id: changelog
|
||||
shell: pwsh
|
||||
run: |
|
||||
$changelogPath = "$env:GITHUB_WORKSPACE\CHANGELOG.md"
|
||||
$lines = Get-Content $changelogPath
|
||||
|
||||
$startIndex = -1
|
||||
for ($i = 0; $i -lt $lines.Count; $i++) {
|
||||
if ($lines[$i] -match '^## \[') {
|
||||
$startIndex = $i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if ($startIndex -eq -1) {
|
||||
throw "No version header found in CHANGELOG.md"
|
||||
}
|
||||
|
||||
$section = @()
|
||||
for ($i = $startIndex + 1; $i -lt $lines.Count; $i++) {
|
||||
if ($lines[$i] -match '^## ') {
|
||||
break
|
||||
}
|
||||
$section += $lines[$i]
|
||||
}
|
||||
|
||||
$joined = $section -join "`n"
|
||||
echo "log<<EOF" >> $env:GITHUB_OUTPUT
|
||||
echo $joined >> $env:GITHUB_OUTPUT
|
||||
echo "EOF" >> $env:GITHUB_OUTPUT
|
||||
|
||||
echo "log=$escaped"
|
||||
|
||||
- name: (09) Create Zip File
|
||||
shell: pwsh
|
||||
run: |
|
||||
$sourceDir = "$Env:GITHUB_WORKSPACE\mRemoteNG\bin\${{ matrix.platform }}\Release"
|
||||
Compress-Archive -Path "$sourceDir\*" -DestinationPath ${{ steps.version.outputs.zipname }}
|
||||
echo "File: ${{ steps.version.outputs.zipname }}"
|
||||
|
||||
- name: (10) Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@aec2ec56f94eb8180ceec724245f64ef008b89f5 # v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.tag }}
|
||||
name: "mRemoteNG ${{ steps.version.outputs.version }} NB ${{ steps.version.outputs.build }}"
|
||||
files: ${{ steps.version.outputs.zipname }}
|
||||
body: |
|
||||
Changes in this Release:
|
||||
${{ steps.changelog.outputs.log }}
|
||||
|
||||
Last Commit Message:
|
||||
${{ steps.version.outputs.message }}
|
||||
|
||||
draft: false
|
||||
prerelease: true
|
||||
126
.github/workflows/add_PR_2_chlog.yml
vendored
Normal file
126
.github/workflows/add_PR_2_chlog.yml
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
name: Update Changelog After Renovate PR Merge
|
||||
|
||||
on:
|
||||
# 1) Auto on pushes to your repo’s default branch (merge commits included)
|
||||
push:
|
||||
branches:
|
||||
- v1.78.2-dev
|
||||
|
||||
# 2) Manual trigger
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dryRun:
|
||||
description: 'Run without committing changes'
|
||||
required: false
|
||||
default: 'true'
|
||||
|
||||
jobs:
|
||||
update-changelog:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Only proceed if…
|
||||
# - manual dispatch
|
||||
# - OR a push to default branch
|
||||
if: |
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.event_name == 'push'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Check for Renovate dependency update
|
||||
id: check-renovate
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
echo "isRenovate=true" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
msg="$(git log -1 --pretty=%B)"
|
||||
if echo "$msg" | grep -q 'chore(deps): update dependency'; then
|
||||
echo "isRenovate=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "isRenovate=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Abort if not a Renovate PR
|
||||
if: steps.check-renovate.outputs.isRenovate == 'false'
|
||||
run: |
|
||||
echo "ℹ️ Last commit is not a Renovate dependency update—skipping."
|
||||
|
||||
- name: Parse Renovate PR info
|
||||
if: steps.check-renovate.outputs.isRenovate == 'true'
|
||||
id: extract
|
||||
shell: pwsh
|
||||
run: |
|
||||
# 1) Determine dryRun
|
||||
$dryRun = '${{ github.event.inputs.dryRun }}'
|
||||
if (-not $dryRun) { $dryRun = 'false' }
|
||||
Write-Host "🔍 dryRun = $dryRun"
|
||||
|
||||
# 2) Read full commit message
|
||||
$fullMsg = git log -1 --pretty=%B
|
||||
Write-Host "📝 Commit message:"; Write-Host $fullMsg
|
||||
|
||||
# 3) Extract PR number
|
||||
if ($fullMsg -match 'Merge pull request #(\d+)') {
|
||||
$prNumber = $matches[1]
|
||||
} else {
|
||||
throw "❌ Could not locate PR number in merge commit"
|
||||
}
|
||||
|
||||
# 4) Extract dependency name & version
|
||||
if ($fullMsg -match 'chore\(deps\): update dependency ([\w\.\-]+) to ([\d\.]+)') {
|
||||
$depName = $matches[1]
|
||||
$depVersion = $matches[2]
|
||||
} else {
|
||||
throw "❌ Could not parse dependency name/version"
|
||||
}
|
||||
|
||||
# 5) Export outputs
|
||||
echo "pr=$prNumber" >> $env:GITHUB_OUTPUT
|
||||
echo "depName=$depName" >> $env:GITHUB_OUTPUT
|
||||
echo "depVersion=$depVersion" >> $env:GITHUB_OUTPUT
|
||||
echo "dryRun=$dryRun" >> $env:GITHUB_OUTPUT
|
||||
|
||||
- name: Update CHANGELOG.md
|
||||
if: steps.check-renovate.outputs.isRenovate == 'true'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$path = "$env:GITHUB_WORKSPACE/CHANGELOG.md"
|
||||
if (-not (Test-Path $path)) { throw "❌ CHANGELOG.md not found" }
|
||||
$lines = Get-Content $path
|
||||
$pr = '${{ steps.extract.outputs.pr }}'
|
||||
$dep = '${{ steps.extract.outputs.depName }}'
|
||||
$ver = '${{ steps.extract.outputs.depVersion }}'
|
||||
$entry = "- #$pr: update dependency $dep to $ver"
|
||||
|
||||
# Find latest version header: ## [x.y.z]
|
||||
$vIndex = $lines.FindIndex({ $_ -match '^## \[\d+\.\d+\.\d+\]' })
|
||||
if ($vIndex -lt 0) { throw "❌ No version header found" }
|
||||
|
||||
# Locate or create "### Dependency update"
|
||||
$depIndex = -1
|
||||
for ($i = $vIndex + 1; $i -lt $lines.Count; $i++) {
|
||||
if ($lines[$i] -match '^### Dependency update') { $depIndex = $i; break }
|
||||
if ($lines[$i] -match '^## ') { break }
|
||||
}
|
||||
if ($depIndex -eq -1) {
|
||||
$lines.Insert($vIndex + 1, '### Dependency update')
|
||||
$depIndex = $vIndex + 1
|
||||
}
|
||||
|
||||
# Insert the changelog entry
|
||||
$lines.Insert($depIndex + 1, $entry)
|
||||
Set-Content -Path $path -Value $lines
|
||||
Write-Host "✅ Inserted in CHANGELOG.md:"; Write-Host " $entry"
|
||||
|
||||
- name: Commit & push
|
||||
if: steps.check-renovate.outputs.isRenovate == 'true' && steps.extract.outputs.dryRun != 'true'
|
||||
run: |
|
||||
git config user.name "github-actions"
|
||||
git config user.email "github-actions@github.com"
|
||||
git add CHANGELOG.md
|
||||
git commit -m "docs: update changelog for #${{ steps.extract.outputs.pr }}"
|
||||
git push
|
||||
130
.github/workflows/build-x86_64.yml
vendored
130
.github/workflows/build-x86_64.yml
vendored
@@ -1,130 +0,0 @@
|
||||
name: Build x86_64
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- v1.77.3-dev
|
||||
|
||||
jobs:
|
||||
Build-Debug-MSI:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
with:
|
||||
vs-version: '17.12.4'
|
||||
|
||||
- name: 03. Restore nuget packages for solution
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: 04. Compile mRemoteNG
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Debug Installer" -p:Platform=x64 /verbosity:normal
|
||||
|
||||
- name: 05. Publish MSI as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debug-msi-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNGInstaller\Installer\bin\x64\Debug\en-US\
|
||||
if-no-files-found: error
|
||||
|
||||
Build-Debug-Portable:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
with:
|
||||
vs-version: '17.8.3'
|
||||
|
||||
- name: 03. Restore nuget packages for solution
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: 04. Compile mRemoteNG
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Debug Portable" -p:Platform=x64 /verbosity:normal
|
||||
|
||||
- name: 05. Publish Portable Binary as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: debug-portable-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNG\bin\x64\Debug Portable\
|
||||
if-no-files-found: error
|
||||
|
||||
Build-Release:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.3.1 # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
with:
|
||||
vs-version: '17.12.4'
|
||||
|
||||
- name: 03. Restore nuget packages for solution
|
||||
shell: pwsh
|
||||
run: |
|
||||
dotnet restore
|
||||
|
||||
- name: 04. Compile mRemoteNG
|
||||
shell: pwsh
|
||||
run: |
|
||||
msbuild "$Env:GITHUB_WORKSPACE\mRemoteNG.sln" -p:Configuration="Release Installer and Portable" -p:Platform=x64 /verbosity:normal
|
||||
|
||||
- name: 05. Publish MSI Binary as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-msi-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNGInstaller\Installer\bin\x64\Release\en-US\
|
||||
if-no-files-found: error
|
||||
|
||||
- name: 06. Publish Portable Binary as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-portable-x86_64
|
||||
path: ${{ github.workspace }}\mRemoteNG\bin\x64\Release
|
||||
if-no-files-found: error
|
||||
|
||||
Create-Release:
|
||||
needs: [Build-Debug-MSI, Build-Debug-Portable, Build-Release]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: 01. Copy repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 02. Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: 03. Create compressed archives # Needs to be done because "actions/download-artifact@v4" is extracting the zipped Artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
zip -r debug-msi-x86_64.zip debug-msi-x86_64/
|
||||
zip -r debug-portable-x86_64.zip debug-portable-x86_64/
|
||||
zip -r release-msi-x86_64.zip release-msi-x86_64/
|
||||
zip -r release-portable-x86_64.zip release-portable-x86_64/
|
||||
|
||||
- name: 04. Create Release
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh release create "v1.77.3-dev-${GITHUB_RUN_NUMBER}" \
|
||||
--title "v1.77.3-dev-${GITHUB_RUN_NUMBER}" \
|
||||
--prerelease \
|
||||
--generate-notes \
|
||||
$GITHUB_WORKSPACE/debug-msi-x86_64.zip \
|
||||
$GITHUB_WORKSPACE/debug-portable-x86_64.zip \
|
||||
$GITHUB_WORKSPACE/release-msi-x86_64.zip \
|
||||
$GITHUB_WORKSPACE/release-portable-x86_64.zip
|
||||
49
.github/workflows/post_2_Reddit.yml
vendored
Normal file
49
.github/workflows/post_2_Reddit.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Post to Reddit via PowerShell
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
post:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Authenticate and post to Reddit
|
||||
shell: pwsh
|
||||
env:
|
||||
CLIENT_ID: ${{ secrets.REDDIT_CLIENT_ID }}
|
||||
CLIENT_SECRET: ${{ secrets.REDDIT_CLIENT_SECRET }}
|
||||
USERNAME: ${{ secrets.REDDIT_USERNAME }}
|
||||
PASSWORD: ${{ secrets.REDDIT_PASSWORD }}
|
||||
SUBREDDIT: ${{ secrets.REDDIT_SUBREDDIT }}
|
||||
run: |
|
||||
# Step 1: Get access token
|
||||
$authHeaders = @{
|
||||
Authorization = "Basic " + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$env:CLIENT_ID:$env:CLIENT_SECRET"))
|
||||
"User-Agent" = "github-to-reddit-pwsh/0.1"
|
||||
}
|
||||
|
||||
$authBody = @{
|
||||
grant_type = "password"
|
||||
username = $env:USERNAME
|
||||
password = $env:PASSWORD
|
||||
}
|
||||
|
||||
$authResponse = Invoke-RestMethod -Uri "https://www.reddit.com/api/v1/access_token" -Method Post -Headers $authHeaders -Body $authBody
|
||||
$token = $authResponse.access_token
|
||||
|
||||
# Step 2: Post to subreddit
|
||||
$postHeaders = @{
|
||||
Authorization = "bearer $token"
|
||||
"User-Agent" = "github-to-reddit-pwsh/0.1"
|
||||
}
|
||||
|
||||
$postBody = @{
|
||||
sr = $env:SUBREDDIT
|
||||
title = "Hello from GitHub Actions (PowerShell)"
|
||||
kind = "self"
|
||||
text = "This post was made using PowerShell in GitHub Actions."
|
||||
}
|
||||
|
||||
$postResponse = Invoke-RestMethod -Uri "https://oauth.reddit.com/api/submit" -Method Post -Headers $postHeaders -Body $postBody
|
||||
Write-Host "Posted: $($postResponse.json.url)"
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -2,6 +2,39 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
## [1.78.2]
|
||||
### Fixed
|
||||
- #2855: Fix missing Username field for HTTP and HTTPS protocols
|
||||
- #2852: Fix XML External Entity (XXE) vulnerability in XML deserialization
|
||||
- #2851: Fix path traversal vulnerability in file operations
|
||||
- #2850: Fix password dialog appearing behind splash screen on startup
|
||||
- #2842: Fix element placement in options window
|
||||
- #2715: Disable WinForms analyzers and suppress WFO1000 build errors for ObjectListView
|
||||
- #2712: VNCEvent_Disconnected send the ProtocolBase based object reference
|
||||
- #2668: fix ssh quickconnect exception
|
||||
- #2611: correct registry path
|
||||
- #2496: use pwfile instead of cleartext password for putty connections
|
||||
- #2734: fix native build for Windows-x64
|
||||
|
||||
### Added
|
||||
|
||||
- #2865: Add configurable connection tab colors to distinguish between different environments
|
||||
- #2864: Add Color property to connections and folders with inheritance support
|
||||
- #2863: Add ARD (Apple Remote Desktop) protocol support for macOS connections
|
||||
- #2728: Add support for building mRemoteNG on Windows ARM64
|
||||
- #2723: Read keyboardhook, gatewayaccesstoken and gatewaycredentialssource from RDP File
|
||||
- #2690: தமிழ் (ta) Translation update
|
||||
- #2643: Registry Settings: enhancements and new settings implementation
|
||||
- #2591: add Clickstudios Passwordstate API connector
|
||||
|
||||
### Updated
|
||||
- #2854: Refactor settings dialog to be opened in dockable panel (for consistency)
|
||||
- #2597: Remember the opened connection file on relaunch
|
||||
- #2502: Updated Polish translation
|
||||
|
||||
### Dependency update
|
||||
- #3bd2fe8: puttyng updated to x64 version (and signed)
|
||||
|
||||
## [1.77.3.1784]
|
||||
### Fixed
|
||||
- #2362: Fix use of sql database
|
||||
|
||||
104
Directory.Packages.props
Normal file
104
Directory.Packages.props
Normal file
@@ -0,0 +1,104 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||
<NoWarn>$(NoWarn);NU1507</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="AWSSDK.Core" Version="4.0.0.32" />
|
||||
<PackageVersion Include="AWSSDK.EC2" Version="4.0.40.4" />
|
||||
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.6.2" />
|
||||
<PackageVersion Include="Castle.Core" Version="5.2.1" />
|
||||
<PackageVersion Include="ConsoleControl" Version="1.3.0" />
|
||||
<PackageVersion Include="ConsoleControlAPI" Version="1.3.0" />
|
||||
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageVersion Include="Cucumber.Messages" Version="30.0.0" />
|
||||
<PackageVersion Include="DockPanelSuite" Version="3.1.1" />
|
||||
<PackageVersion Include="DockPanelSuite.ThemeVS2015" Version="3.1.1" />
|
||||
<PackageVersion Include="envdte" Version="17.14.40260" />
|
||||
<PackageVersion Include="Gherkin" Version="35.1.0" />
|
||||
<PackageVersion Include="Google.Protobuf" Version="3.32.1" />
|
||||
<PackageVersion Include="LiteDB" Version="5.0.21" />
|
||||
<PackageVersion Include="log4net" Version="3.2.0" />
|
||||
<PackageVersion Include="Microsoft.Data.SqlClient" Version="6.1.1" />
|
||||
<PackageVersion Include="Microsoft.Data.SqlClient.SNI" Version="6.0.2" />
|
||||
<PackageVersion Include="Microsoft.Data.SqlClient.SNI.runtime" Version="6.0.2" />
|
||||
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.9" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
||||
<PackageVersion Include="Microsoft.NETCore.Platforms" Version="7.0.4" />
|
||||
<PackageVersion Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
||||
<PackageVersion Include="Microsoft.VisualStudio.TextTemplating.VSHost" Version="17.14.40265" />
|
||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.3537.50" />
|
||||
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.135" />
|
||||
<PackageVersion Include="Microsoft-WindowsAPICodePack-Shell" Version="1.1.5" />
|
||||
<PackageVersion Include="MySql.Data" Version="9.4.0" />
|
||||
<PackageVersion Include="NETStandard.Library" Version="2.0.3" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageVersion Include="Newtonsoft.Json.Schema" Version="4.0.1" />
|
||||
<PackageVersion Include="NSubstitute" Version="5.3.0" />
|
||||
<PackageVersion Include="NUnit" Version="4.4.0" />
|
||||
<PackageVersion Include="NUnit.Console" Version="3.20.1" />
|
||||
<PackageVersion Include="NUnit.ConsoleRunner" Version="3.20.1" />
|
||||
<PackageVersion Include="NUnit.Extension.TeamCityEventListener" Version="1.0.10" />
|
||||
<PackageVersion Include="NUnit.Runners" Version="3.12.0" />
|
||||
<PackageVersion Include="NUnit3TestAdapter" Version="5.2.0" />
|
||||
<PackageVersion Include="OpenCover" Version="4.7.1221" />
|
||||
<PackageVersion Include="Renci.SshNet.Async" Version="1.4.0" />
|
||||
<PackageVersion Include="ReportGenerator" Version="5.4.17" />
|
||||
<PackageVersion Include="runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="runtime.native.System" Version="4.3.1" />
|
||||
<PackageVersion Include="runtime.native.System.IO.Compression" Version="4.3.2" />
|
||||
<PackageVersion Include="runtime.native.System.Net.Http" Version="4.3.1" />
|
||||
<PackageVersion Include="runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl" Version="4.3.3" />
|
||||
<PackageVersion Include="SSH.NET" Version="2025.0.0" />
|
||||
<PackageVersion Include="System.Buffers" Version="4.6.1" />
|
||||
<PackageVersion Include="System.Configuration.ConfigurationManager" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Collections.Immutable" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Console" Version="4.3.1" />
|
||||
<PackageVersion Include="System.Data.Common" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Diagnostics.DiagnosticSource" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Drawing.Common" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Diagnostics.EventLog" Version="9.0.9" />
|
||||
<PackageVersion Include="System.DirectoryServices" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Dynamic.Runtime" Version="4.3.0" />
|
||||
<PackageVersion Include="System.IO.Pipelines" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Formats.Asn1" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Memory" Version="4.6.3" />
|
||||
<PackageVersion Include="System.Net.Http" Version="4.3.4" />
|
||||
<PackageVersion Include="System.Net.Primitives" Version="4.3.1" />
|
||||
<PackageVersion Include="System.Net.Sockets" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Reflection.Emit" Version="4.7.0" />
|
||||
<PackageVersion Include="System.Reflection.Emit.ILGeneration" Version="4.7.0" />
|
||||
<PackageVersion Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
|
||||
<PackageVersion Include="System.Reflection.Metadata" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Reflection.TypeExtensions" Version="4.7.0" />
|
||||
<PackageVersion Include="System.Resources.ResourceManager" Version="4.3.0" />
|
||||
<PackageVersion Include="System.Runtime" Version="4.3.1" />
|
||||
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
|
||||
<PackageVersion Include="System.Runtime.Extensions" Version="4.3.1" />
|
||||
<PackageVersion Include="System.Security.AccessControl" Version="6.0.1" />
|
||||
<PackageVersion Include="System.Security.Cryptography.Algorithms" Version="4.3.1" />
|
||||
<PackageVersion Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||
<PackageVersion Include="System.Security.Cryptography.OpenSsl" Version="5.0.0" />
|
||||
<PackageVersion Include="System.Security.Cryptography.ProtectedData" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Security.Cryptography.X509Certificates" Version="4.3.2" />
|
||||
<PackageVersion Include="System.Security.Permissions" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
|
||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Text.Json" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageVersion Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
|
||||
<PackageVersion Include="System.ValueTuple" Version="4.6.1" />
|
||||
<PackageVersion Include="System.Windows.Extensions" Version="9.0.9" />
|
||||
<PackageVersion Include="System.Xml.ReaderWriter" Version="4.3.1" />
|
||||
<PackageVersion Include="VncSharpCore" Version="1.2.1" />
|
||||
<PackageVersion Include="ZstdSharp.Port" Version="0.8.6" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -257,15 +257,9 @@ public class PasswordstateInterface
|
||||
|
||||
return ""+textWriter.ToString();
|
||||
}
|
||||
private class PasswordFinder : IPasswordFinder
|
||||
private class PasswordFinder(string password) : IPasswordFinder
|
||||
{
|
||||
private string password;
|
||||
|
||||
public PasswordFinder(string password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
private string password = password;
|
||||
|
||||
public char[] GetPassword()
|
||||
{
|
||||
|
||||
@@ -58,10 +58,7 @@ namespace SecretServerAuthentication.DSS
|
||||
/// <param name="refresh_token">The refresh token. Required when refreshing a token.</param>
|
||||
/// <returns>Successful retrieval of an access token</returns>
|
||||
/// <exception cref="ApiException">A server side error occurred.</exception>
|
||||
public System.Threading.Tasks.Task<TokenResponse> AuthorizeAsync(Grant_type grant_type, string username, string password, string refresh_token, string OTP)
|
||||
{
|
||||
return AuthorizeAsync(grant_type, username, password, refresh_token, System.Threading.CancellationToken.None, OTP);
|
||||
}
|
||||
public System.Threading.Tasks.Task<TokenResponse> AuthorizeAsync(Grant_type grant_type, string username, string password, string refresh_token, string OTP) => AuthorizeAsync(grant_type, username, password, refresh_token, System.Threading.CancellationToken.None, OTP);
|
||||
|
||||
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||
/// <summary>Retrieve or Refresh Access Token</summary>
|
||||
@@ -355,10 +352,7 @@ namespace SecretServerAuthentication.DSS
|
||||
Headers = headers;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
|
||||
}
|
||||
public override string ToString() => string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
|
||||
}
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.14.8.0 (NJsonSchema v10.5.2.0 (Newtonsoft.Json v11.0.0.0))")]
|
||||
|
||||
@@ -223,15 +223,9 @@ public class SecretServerInterface
|
||||
|
||||
return ""+textWriter.ToString();
|
||||
}
|
||||
private class PasswordFinder : IPasswordFinder
|
||||
private class PasswordFinder(string password) : IPasswordFinder
|
||||
{
|
||||
private string password;
|
||||
|
||||
public PasswordFinder(string password)
|
||||
{
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
private string password = password;
|
||||
|
||||
public char[] GetPassword()
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Library</OutputType>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<Platforms>x64</Platforms>
|
||||
<Platforms>x64;arm64</Platforms>
|
||||
<Configurations>Debug;Release;Debug Portable;Release Portable;Deploy to github</Configurations>
|
||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion>10.0.26100.0</SupportedOSPlatformVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Portable|x64'">
|
||||
<Optimize>True</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Portable|arm64'">
|
||||
<Optimize>True</Optimize>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AWSSDK.Core" Version="3.7.402.1" />
|
||||
<PackageReference Include="AWSSDK.EC2" Version="3.7.430.2" />
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.5.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="AWSSDK.Core" />
|
||||
<PackageReference Include="AWSSDK.EC2" />
|
||||
<PackageReference Include="BouncyCastle.Cryptography" />
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="AWS\AWSConnectionForm.cs" />
|
||||
<Compile Update="CPS\CPSConnectionForm.cs" />
|
||||
<Compile Update="DSS\SSConnectionForm.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -46,18 +46,14 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// These items allow combo boxes to remember a value and its description.
|
||||
/// </summary>
|
||||
public class ComboBoxItem
|
||||
/// <remarks>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="description"></param>
|
||||
public class ComboBoxItem(Object key, String description)
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="description"></param>
|
||||
public ComboBoxItem(Object key, String description) {
|
||||
this.key = key;
|
||||
this.description = description;
|
||||
}
|
||||
private readonly String description;
|
||||
private readonly String description = description;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -65,7 +61,7 @@ namespace BrightIdeasSoftware
|
||||
public Object Key {
|
||||
get { return key; }
|
||||
}
|
||||
private readonly Object key;
|
||||
private readonly Object key = key;
|
||||
|
||||
/// <summary>
|
||||
/// Returns a string that represents the current object.
|
||||
|
||||
@@ -158,15 +158,12 @@ namespace BrightIdeasSoftware
|
||||
/// This class isn't intended to be used directly, but it is left as a public
|
||||
/// class just in case someone wants to subclass it.
|
||||
/// </remarks>
|
||||
public class FastObjectListDataSource : AbstractVirtualListDataSource
|
||||
/// <remarks>
|
||||
/// Create a FastObjectListDataSource
|
||||
/// </remarks>
|
||||
/// <param name="listView"></param>
|
||||
public class FastObjectListDataSource(FastObjectListView listView) : AbstractVirtualListDataSource(listView)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a FastObjectListDataSource
|
||||
/// </summary>
|
||||
/// <param name="listView"></param>
|
||||
public FastObjectListDataSource(FastObjectListView listView)
|
||||
: base(listView) {
|
||||
}
|
||||
|
||||
#region IVirtualListDataSource Members
|
||||
|
||||
|
||||
@@ -185,15 +185,11 @@ namespace BrightIdeasSoftware
|
||||
/// A model object must satisfy all filters to be included.
|
||||
/// If there are no filters, all model objects are included
|
||||
/// </summary>
|
||||
public class CompositeAllFilter : CompositeFilter {
|
||||
|
||||
/// <summary>
|
||||
/// Create a filter
|
||||
/// </summary>
|
||||
/// <param name="filters"></param>
|
||||
public CompositeAllFilter(List<IModelFilter> filters)
|
||||
: base(filters) {
|
||||
}
|
||||
/// <remarks>
|
||||
/// Create a filter
|
||||
/// </remarks>
|
||||
/// <param name="filters"></param>
|
||||
public class CompositeAllFilter(List<IModelFilter> filters) : CompositeFilter(filters) {
|
||||
|
||||
/// <summary>
|
||||
/// Decide whether or not the given model should be included by the filter
|
||||
@@ -215,15 +211,11 @@ namespace BrightIdeasSoftware
|
||||
/// A model object must only satisfy one of the filters to be included.
|
||||
/// If there are no filters, all model objects are included
|
||||
/// </summary>
|
||||
public class CompositeAnyFilter : CompositeFilter {
|
||||
|
||||
/// <summary>
|
||||
/// Create a filter from the given filters
|
||||
/// </summary>
|
||||
/// <param name="filters"></param>
|
||||
public CompositeAnyFilter(List<IModelFilter> filters)
|
||||
: base(filters) {
|
||||
}
|
||||
/// <remarks>
|
||||
/// Create a filter from the given filters
|
||||
/// </remarks>
|
||||
/// <param name="filters"></param>
|
||||
public class CompositeAnyFilter(List<IModelFilter> filters) : CompositeFilter(filters) {
|
||||
|
||||
/// <summary>
|
||||
/// Decide whether or not the given model should be included by the filter
|
||||
|
||||
@@ -50,7 +50,13 @@ namespace BrightIdeasSoftware
|
||||
/// <para>This is used by normal (non-virtual) ObjectListViews. Virtual lists use
|
||||
/// ModelObjectComparer</para>
|
||||
/// </remarks>
|
||||
public class ColumnComparer : IComparer, IComparer<OLVListItem>
|
||||
/// <remarks>
|
||||
/// Create a ColumnComparer that will order the rows in a list view according
|
||||
/// to the values in a given column
|
||||
/// </remarks>
|
||||
/// <param name="col">The column whose values will be compared</param>
|
||||
/// <param name="order">The ordering for column values</param>
|
||||
public class ColumnComparer(OLVColumn col, SortOrder order) : IComparer, IComparer<OLVListItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the method that will be used to compare two strings.
|
||||
@@ -63,18 +69,6 @@ namespace BrightIdeasSoftware
|
||||
}
|
||||
private static StringCompareDelegate stringComparer;
|
||||
|
||||
/// <summary>
|
||||
/// Create a ColumnComparer that will order the rows in a list view according
|
||||
/// to the values in a given column
|
||||
/// </summary>
|
||||
/// <param name="col">The column whose values will be compared</param>
|
||||
/// <param name="order">The ordering for column values</param>
|
||||
public ColumnComparer(OLVColumn col, SortOrder order)
|
||||
{
|
||||
this.column = col;
|
||||
this.sortOrder = order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a ColumnComparer that will order the rows in a list view according
|
||||
/// to the values in a given column, and by a secondary column if the primary
|
||||
@@ -165,8 +159,8 @@ namespace BrightIdeasSoftware
|
||||
return StringComparer(x, y);
|
||||
}
|
||||
|
||||
private OLVColumn column;
|
||||
private SortOrder sortOrder;
|
||||
private OLVColumn column = col;
|
||||
private SortOrder sortOrder = order;
|
||||
private ColumnComparer secondComparer;
|
||||
}
|
||||
|
||||
@@ -175,15 +169,12 @@ namespace BrightIdeasSoftware
|
||||
/// This comparer sort list view groups. OLVGroups have a "SortValue" property,
|
||||
/// which is used if present. Otherwise, the titles of the groups will be compared.
|
||||
/// </summary>
|
||||
public class OLVGroupComparer : IComparer<OLVGroup>
|
||||
/// <remarks>
|
||||
/// Create a group comparer
|
||||
/// </remarks>
|
||||
/// <param name="order">The ordering for column values</param>
|
||||
public class OLVGroupComparer(SortOrder order) : IComparer<OLVGroup>
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a group comparer
|
||||
/// </summary>
|
||||
/// <param name="order">The ordering for column values</param>
|
||||
public OLVGroupComparer(SortOrder order) {
|
||||
this.sortOrder = order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compare the two groups. OLVGroups have a "SortValue" property,
|
||||
@@ -207,7 +198,7 @@ namespace BrightIdeasSoftware
|
||||
return result;
|
||||
}
|
||||
|
||||
private SortOrder sortOrder;
|
||||
private SortOrder sortOrder = order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -217,7 +208,12 @@ namespace BrightIdeasSoftware
|
||||
/// <para>This is used by virtual ObjectListViews. Non-virtual lists use
|
||||
/// ColumnComparer</para>
|
||||
/// </remarks>
|
||||
public class ModelObjectComparer : IComparer, IComparer<object>
|
||||
/// <remarks>
|
||||
/// Create a model object comparer
|
||||
/// </remarks>
|
||||
/// <param name="col"></param>
|
||||
/// <param name="order"></param>
|
||||
public class ModelObjectComparer(OLVColumn col, SortOrder order) : IComparer, IComparer<object>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the method that will be used to compare two strings.
|
||||
@@ -230,17 +226,6 @@ namespace BrightIdeasSoftware
|
||||
}
|
||||
private static StringCompareDelegate stringComparer;
|
||||
|
||||
/// <summary>
|
||||
/// Create a model object comparer
|
||||
/// </summary>
|
||||
/// <param name="col"></param>
|
||||
/// <param name="order"></param>
|
||||
public ModelObjectComparer(OLVColumn col, SortOrder order)
|
||||
{
|
||||
this.column = col;
|
||||
this.sortOrder = order;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a model object comparer with a secondary sorting column
|
||||
/// </summary>
|
||||
@@ -318,8 +303,8 @@ namespace BrightIdeasSoftware
|
||||
return StringComparer(x, y);
|
||||
}
|
||||
|
||||
private OLVColumn column;
|
||||
private SortOrder sortOrder;
|
||||
private OLVColumn column = col;
|
||||
private SortOrder sortOrder = order;
|
||||
private ModelObjectComparer secondComparer;
|
||||
|
||||
#region IComparer<object> Members
|
||||
|
||||
@@ -878,25 +878,16 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// Let the world know that a cell edit operation is beginning or ending
|
||||
/// </summary>
|
||||
public class CellEditEventArgs : EventArgs
|
||||
/// <remarks>
|
||||
/// Create an event args
|
||||
/// </remarks>
|
||||
/// <param name="column"></param>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="cellBounds"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="subItemIndex"></param>
|
||||
public class CellEditEventArgs(OLVColumn column, Control control, Rectangle cellBounds, OLVListItem item, int subItemIndex) : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an event args
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
/// <param name="control"></param>
|
||||
/// <param name="cellBounds"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="subItemIndex"></param>
|
||||
public CellEditEventArgs(OLVColumn column, Control control, Rectangle cellBounds, OLVListItem item, int subItemIndex) {
|
||||
this.Control = control;
|
||||
this.column = column;
|
||||
this.cellBounds = cellBounds;
|
||||
this.listViewItem = item;
|
||||
this.rowObject = item.RowObject;
|
||||
this.subItemIndex = subItemIndex;
|
||||
this.value = column.GetValue(item.RowObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Change this to true to cancel the cell editing operation.
|
||||
@@ -917,7 +908,7 @@ namespace BrightIdeasSoftware
|
||||
/// entered and commit that value to the model. Changing the control during the finishing
|
||||
/// event has no effect.
|
||||
/// </summary>
|
||||
public Control Control;
|
||||
public Control Control = control;
|
||||
|
||||
/// <summary>
|
||||
/// The column of the cell that is going to be or has been edited.
|
||||
@@ -925,7 +916,7 @@ namespace BrightIdeasSoftware
|
||||
public OLVColumn Column {
|
||||
get { return this.column; }
|
||||
}
|
||||
private OLVColumn column;
|
||||
private OLVColumn column = column;
|
||||
|
||||
/// <summary>
|
||||
/// The model object of the row of the cell that is going to be or has been edited.
|
||||
@@ -933,7 +924,7 @@ namespace BrightIdeasSoftware
|
||||
public Object RowObject {
|
||||
get { return this.rowObject; }
|
||||
}
|
||||
private Object rowObject;
|
||||
private Object rowObject = item.RowObject;
|
||||
|
||||
/// <summary>
|
||||
/// The listview item of the cell that is going to be or has been edited.
|
||||
@@ -941,7 +932,7 @@ namespace BrightIdeasSoftware
|
||||
public OLVListItem ListViewItem {
|
||||
get { return this.listViewItem; }
|
||||
}
|
||||
private OLVListItem listViewItem;
|
||||
private OLVListItem listViewItem = item;
|
||||
|
||||
/// <summary>
|
||||
/// The data value of the cell as it stands in the control.
|
||||
@@ -959,7 +950,7 @@ namespace BrightIdeasSoftware
|
||||
public int SubItemIndex {
|
||||
get { return this.subItemIndex; }
|
||||
}
|
||||
private int subItemIndex;
|
||||
private int subItemIndex = subItemIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The data value of the cell before the edit operation began.
|
||||
@@ -967,7 +958,7 @@ namespace BrightIdeasSoftware
|
||||
public Object Value {
|
||||
get { return this.value; }
|
||||
}
|
||||
private Object value;
|
||||
private Object value = column.GetValue(item.RowObject);
|
||||
|
||||
/// <summary>
|
||||
/// The bounds of the cell that is going to be or has been edited.
|
||||
@@ -975,7 +966,7 @@ namespace BrightIdeasSoftware
|
||||
public Rectangle CellBounds {
|
||||
get { return this.cellBounds; }
|
||||
}
|
||||
private Rectangle cellBounds;
|
||||
private Rectangle cellBounds = cellBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the control used for editing should be auto matically disposed
|
||||
@@ -1160,25 +1151,22 @@ namespace BrightIdeasSoftware
|
||||
}
|
||||
private SortOrder secondarySortOrder;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This event is triggered when the contents of a list have changed
|
||||
/// and we want the world to have a chance to filter the list.
|
||||
/// </summary>
|
||||
public class FilterEventArgs : EventArgs
|
||||
/// <remarks>
|
||||
/// Create a FilterEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="objects"></param>
|
||||
public class FilterEventArgs(IEnumerable objects) : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a FilterEventArgs
|
||||
/// </summary>
|
||||
/// <param name="objects"></param>
|
||||
public FilterEventArgs(IEnumerable objects) {
|
||||
this.Objects = objects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets what objects are being filtered
|
||||
/// </summary>
|
||||
public IEnumerable Objects;
|
||||
public IEnumerable Objects = objects;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets what objects survived the filtering
|
||||
@@ -1267,17 +1255,13 @@ namespace BrightIdeasSoftware
|
||||
/// <remarks>
|
||||
/// When used with a virtual list, OldObjects will always be null.
|
||||
/// </remarks>
|
||||
public class ItemsChangingEventArgs : CancellableEventArgs
|
||||
/// <remarks>
|
||||
/// Create ItemsChangingEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="oldObjects"></param>
|
||||
/// <param name="newObjects"></param>
|
||||
public class ItemsChangingEventArgs(IEnumerable oldObjects, IEnumerable newObjects) : CancellableEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create ItemsChangingEventArgs
|
||||
/// </summary>
|
||||
/// <param name="oldObjects"></param>
|
||||
/// <param name="newObjects"></param>
|
||||
public ItemsChangingEventArgs(IEnumerable oldObjects, IEnumerable newObjects) {
|
||||
this.oldObjects = oldObjects;
|
||||
this.NewObjects = newObjects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the objects that were in the list before it change.
|
||||
@@ -1286,47 +1270,40 @@ namespace BrightIdeasSoftware
|
||||
public IEnumerable OldObjects {
|
||||
get { return oldObjects; }
|
||||
}
|
||||
private IEnumerable oldObjects;
|
||||
private IEnumerable oldObjects = oldObjects;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the objects that will be in the list after it changes.
|
||||
/// </summary>
|
||||
public IEnumerable NewObjects;
|
||||
public IEnumerable NewObjects = newObjects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This event is triggered by RemoveObjects before any change has been made to the list.
|
||||
/// </summary>
|
||||
public class ItemsRemovingEventArgs : CancellableEventArgs
|
||||
/// <remarks>
|
||||
/// Create an ItemsRemovingEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="objectsToRemove"></param>
|
||||
public class ItemsRemovingEventArgs(ICollection objectsToRemove) : CancellableEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an ItemsRemovingEventArgs
|
||||
/// </summary>
|
||||
/// <param name="objectsToRemove"></param>
|
||||
public ItemsRemovingEventArgs(ICollection objectsToRemove) {
|
||||
this.ObjectsToRemove = objectsToRemove;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the objects that will be removed
|
||||
/// </summary>
|
||||
public ICollection ObjectsToRemove;
|
||||
public ICollection ObjectsToRemove = objectsToRemove;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered after the user types into a list
|
||||
/// </summary>
|
||||
public class AfterSearchingEventArgs : EventArgs
|
||||
/// <remarks>
|
||||
/// Create an AfterSearchingEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="stringToFind"></param>
|
||||
/// <param name="indexSelected"></param>
|
||||
public class AfterSearchingEventArgs(string stringToFind, int indexSelected) : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an AfterSearchingEventArgs
|
||||
/// </summary>
|
||||
/// <param name="stringToFind"></param>
|
||||
/// <param name="indexSelected"></param>
|
||||
public AfterSearchingEventArgs(string stringToFind, int indexSelected) {
|
||||
this.stringToFind = stringToFind;
|
||||
this.indexSelected = indexSelected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string that was actually searched for
|
||||
@@ -1334,7 +1311,7 @@ namespace BrightIdeasSoftware
|
||||
public string StringToFind {
|
||||
get { return this.stringToFind; }
|
||||
}
|
||||
private string stringToFind;
|
||||
private string stringToFind = stringToFind;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether an the event handler already handled this event
|
||||
@@ -1348,23 +1325,19 @@ namespace BrightIdeasSoftware
|
||||
public int IndexSelected {
|
||||
get { return this.indexSelected; }
|
||||
}
|
||||
private int indexSelected;
|
||||
private int indexSelected = indexSelected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the user types into a list
|
||||
/// </summary>
|
||||
public class BeforeSearchingEventArgs : CancellableEventArgs
|
||||
/// <remarks>
|
||||
/// Create BeforeSearchingEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="stringToFind"></param>
|
||||
/// <param name="startSearchFrom"></param>
|
||||
public class BeforeSearchingEventArgs(string stringToFind, int startSearchFrom) : CancellableEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create BeforeSearchingEventArgs
|
||||
/// </summary>
|
||||
/// <param name="stringToFind"></param>
|
||||
/// <param name="startSearchFrom"></param>
|
||||
public BeforeSearchingEventArgs(string stringToFind, int startSearchFrom) {
|
||||
this.StringToFind = stringToFind;
|
||||
this.StartSearchFrom = startSearchFrom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the string that will be found by the search routine
|
||||
@@ -1372,12 +1345,12 @@ namespace BrightIdeasSoftware
|
||||
/// <remarks>Modifying this value does not modify the memory of what the user has typed.
|
||||
/// When the user next presses a character, the search string will revert to what
|
||||
/// the user has actually typed.</remarks>
|
||||
public string StringToFind;
|
||||
public string StringToFind = stringToFind;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the first row that will be considered to matching.
|
||||
/// </summary>
|
||||
public int StartSearchFrom;
|
||||
public int StartSearchFrom = startSearchFrom;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2035,27 +2008,20 @@ namespace BrightIdeasSoftware
|
||||
return string.Format("NewHotCellHitLocation: {0}, HotCellHitLocationEx: {1}, NewHotColumnIndex: {2}, NewHotRowIndex: {3}, HotGroup: {4}", this.newHotCellHitLocation, this.hotCellHitLocationEx, this.newHotColumnIndex, this.newHotRowIndex, this.hotGroup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Let the world know that a checkbox on a subitem is changing
|
||||
/// </summary>
|
||||
public class SubItemCheckingEventArgs : CancellableEventArgs
|
||||
/// <remarks>
|
||||
/// Create a new event block
|
||||
/// </remarks>
|
||||
/// <param name="column"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="subItemIndex"></param>
|
||||
/// <param name="currentValue"></param>
|
||||
/// <param name="newValue"></param>
|
||||
public class SubItemCheckingEventArgs(OLVColumn column, OLVListItem item, int subItemIndex, CheckState currentValue, CheckState newValue) : CancellableEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new event block
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
/// <param name="item"></param>
|
||||
/// <param name="subItemIndex"></param>
|
||||
/// <param name="currentValue"></param>
|
||||
/// <param name="newValue"></param>
|
||||
public SubItemCheckingEventArgs(OLVColumn column, OLVListItem item, int subItemIndex, CheckState currentValue, CheckState newValue) {
|
||||
this.column = column;
|
||||
this.listViewItem = item;
|
||||
this.subItemIndex = subItemIndex;
|
||||
this.currentValue = currentValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The column of the cell that is having its checkbox changed.
|
||||
@@ -2063,7 +2029,7 @@ namespace BrightIdeasSoftware
|
||||
public OLVColumn Column {
|
||||
get { return this.column; }
|
||||
}
|
||||
private OLVColumn column;
|
||||
private OLVColumn column = column;
|
||||
|
||||
/// <summary>
|
||||
/// The model object of the row of the cell that is having its checkbox changed.
|
||||
@@ -2078,7 +2044,7 @@ namespace BrightIdeasSoftware
|
||||
public OLVListItem ListViewItem {
|
||||
get { return this.listViewItem; }
|
||||
}
|
||||
private OLVListItem listViewItem;
|
||||
private OLVListItem listViewItem = item;
|
||||
|
||||
/// <summary>
|
||||
/// The current check state of the cell.
|
||||
@@ -2086,7 +2052,7 @@ namespace BrightIdeasSoftware
|
||||
public CheckState CurrentValue {
|
||||
get { return this.currentValue; }
|
||||
}
|
||||
private CheckState currentValue;
|
||||
private CheckState currentValue = currentValue;
|
||||
|
||||
/// <summary>
|
||||
/// The proposed new check state of the cell.
|
||||
@@ -2095,7 +2061,7 @@ namespace BrightIdeasSoftware
|
||||
get { return this.newValue; }
|
||||
set { this.newValue = value; }
|
||||
}
|
||||
private CheckState newValue;
|
||||
private CheckState newValue = newValue;
|
||||
|
||||
/// <summary>
|
||||
/// The index of the cell that is going to be or has been edited.
|
||||
@@ -2103,21 +2069,18 @@ namespace BrightIdeasSoftware
|
||||
public int SubItemIndex {
|
||||
get { return this.subItemIndex; }
|
||||
}
|
||||
private int subItemIndex;
|
||||
private int subItemIndex = subItemIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This event argument block is used when groups are created for a list.
|
||||
/// </summary>
|
||||
public class CreateGroupsEventArgs : EventArgs
|
||||
/// <remarks>
|
||||
/// Create a CreateGroupsEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="parms"></param>
|
||||
public class CreateGroupsEventArgs(GroupingParameters parms) : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a CreateGroupsEventArgs
|
||||
/// </summary>
|
||||
/// <param name="parms"></param>
|
||||
public CreateGroupsEventArgs(GroupingParameters parms) {
|
||||
this.parameters = parms;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings that control the creation of groups
|
||||
@@ -2125,7 +2088,7 @@ namespace BrightIdeasSoftware
|
||||
public GroupingParameters Parameters {
|
||||
get { return this.parameters; }
|
||||
}
|
||||
private GroupingParameters parameters;
|
||||
private GroupingParameters parameters = parms;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the groups that should be used
|
||||
@@ -2151,16 +2114,12 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// This event argument block is used when the text of a group task is clicked
|
||||
/// </summary>
|
||||
public class GroupTaskClickedEventArgs : EventArgs
|
||||
/// <remarks>
|
||||
/// Create a GroupTaskClickedEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="group"></param>
|
||||
public class GroupTaskClickedEventArgs(OLVGroup group) : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a GroupTaskClickedEventArgs
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
public GroupTaskClickedEventArgs(OLVGroup group)
|
||||
{
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets which group was clicked
|
||||
@@ -2169,7 +2128,7 @@ namespace BrightIdeasSoftware
|
||||
{
|
||||
get { return this.group; }
|
||||
}
|
||||
private readonly OLVGroup group;
|
||||
private readonly OLVGroup group = group;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2207,18 +2166,13 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// This event argument block is used when the state of group has changed (collapsed, selected)
|
||||
/// </summary>
|
||||
public class GroupStateChangedEventArgs : EventArgs {
|
||||
/// <summary>
|
||||
/// Create a GroupStateChangedEventArgs
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="oldState"> </param>
|
||||
/// <param name="newState"> </param>
|
||||
public GroupStateChangedEventArgs(OLVGroup group, GroupState oldState, GroupState newState) {
|
||||
this.group = group;
|
||||
this.oldState = oldState;
|
||||
this.newState = newState;
|
||||
}
|
||||
/// <remarks>
|
||||
/// Create a GroupStateChangedEventArgs
|
||||
/// </remarks>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="oldState"> </param>
|
||||
/// <param name="newState"> </param>
|
||||
public class GroupStateChangedEventArgs(OLVGroup group, GroupState oldState, GroupState newState) : EventArgs {
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the group was collapsed by this event
|
||||
@@ -2291,7 +2245,7 @@ namespace BrightIdeasSoftware
|
||||
get { return this.group; }
|
||||
}
|
||||
|
||||
private readonly OLVGroup group;
|
||||
private readonly OLVGroup group = group;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the previous state of the group
|
||||
@@ -2300,7 +2254,7 @@ namespace BrightIdeasSoftware
|
||||
get { return this.oldState; }
|
||||
}
|
||||
|
||||
private readonly GroupState oldState;
|
||||
private readonly GroupState oldState = oldState;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -2310,7 +2264,7 @@ namespace BrightIdeasSoftware
|
||||
get { return this.newState; }
|
||||
}
|
||||
|
||||
private readonly GroupState newState;
|
||||
private readonly GroupState newState = newState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -311,18 +311,14 @@ namespace BrightIdeasSoftware
|
||||
/// <remarks>
|
||||
/// Munger uses a chain of these resolve a dotted aspect name.
|
||||
/// </remarks>
|
||||
public class SimpleMunger
|
||||
/// <remarks>
|
||||
/// Create a SimpleMunger
|
||||
/// </remarks>
|
||||
/// <param name="aspectName"></param>
|
||||
public class SimpleMunger(String aspectName)
|
||||
{
|
||||
#region Life and death
|
||||
|
||||
/// <summary>
|
||||
/// Create a SimpleMunger
|
||||
/// </summary>
|
||||
/// <param name="aspectName"></param>
|
||||
public SimpleMunger(String aspectName)
|
||||
{
|
||||
this.aspectName = aspectName;
|
||||
}
|
||||
#region Life and death
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -344,7 +340,7 @@ namespace BrightIdeasSoftware
|
||||
public string AspectName {
|
||||
get { return aspectName; }
|
||||
}
|
||||
private readonly string aspectName;
|
||||
private readonly string aspectName = aspectName;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -494,19 +490,14 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// These exceptions are raised when a munger finds something it cannot process
|
||||
/// </summary>
|
||||
public class MungerException : ApplicationException
|
||||
/// <remarks>
|
||||
/// Create a MungerException
|
||||
/// </remarks>
|
||||
/// <param name="munger"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="ex"></param>
|
||||
public class MungerException(SimpleMunger munger, object target, Exception ex) : ApplicationException("Munger failed", ex)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a MungerException
|
||||
/// </summary>
|
||||
/// <param name="munger"></param>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="ex"></param>
|
||||
public MungerException(SimpleMunger munger, object target, Exception ex)
|
||||
: base("Munger failed", ex) {
|
||||
this.munger = munger;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the munger that raised the exception
|
||||
@@ -514,7 +505,7 @@ namespace BrightIdeasSoftware
|
||||
public SimpleMunger Munger {
|
||||
get { return munger; }
|
||||
}
|
||||
private readonly SimpleMunger munger;
|
||||
private readonly SimpleMunger munger = munger;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the target that threw the exception
|
||||
@@ -522,7 +513,7 @@ namespace BrightIdeasSoftware
|
||||
public object Target {
|
||||
get { return target; }
|
||||
}
|
||||
private readonly object target;
|
||||
private readonly object target = target;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -309,12 +309,9 @@ namespace BrightIdeasSoftware
|
||||
/// A default implementation of the IOwnerDataCallback interface
|
||||
/// </summary>
|
||||
[Guid("6FC61F50-80E8-49b4-B200-3F38D3865ABD")]
|
||||
internal class OwnerDataCallbackImpl : IOwnerDataCallback
|
||||
internal class OwnerDataCallbackImpl(VirtualObjectListView olv) : IOwnerDataCallback
|
||||
{
|
||||
public OwnerDataCallbackImpl(VirtualObjectListView olv) {
|
||||
this.olv = olv;
|
||||
}
|
||||
VirtualObjectListView olv;
|
||||
VirtualObjectListView olv = olv;
|
||||
|
||||
#region IOwnerDataCallback Members
|
||||
|
||||
|
||||
@@ -145,20 +145,17 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// A do-nothing implementation of the VirtualListDataSource interface.
|
||||
/// </summary>
|
||||
public class AbstractVirtualListDataSource : IVirtualListDataSource, IFilterableDataSource
|
||||
/// <remarks>
|
||||
/// Creates an AbstractVirtualListDataSource
|
||||
/// </remarks>
|
||||
/// <param name="listView"></param>
|
||||
public class AbstractVirtualListDataSource(VirtualObjectListView listView) : IVirtualListDataSource, IFilterableDataSource
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates an AbstractVirtualListDataSource
|
||||
/// </summary>
|
||||
/// <param name="listView"></param>
|
||||
public AbstractVirtualListDataSource(VirtualObjectListView listView) {
|
||||
this.listView = listView;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The list view that this data source is giving information to.
|
||||
/// </summary>
|
||||
protected VirtualObjectListView listView;
|
||||
protected VirtualObjectListView listView = listView;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -295,15 +292,12 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// This class mimics the behavior of VirtualObjectListView v1.x.
|
||||
/// </summary>
|
||||
public class VirtualListVersion1DataSource : AbstractVirtualListDataSource
|
||||
/// <remarks>
|
||||
/// Creates a VirtualListVersion1DataSource
|
||||
/// </remarks>
|
||||
/// <param name="listView"></param>
|
||||
public class VirtualListVersion1DataSource(VirtualObjectListView listView) : AbstractVirtualListDataSource(listView)
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a VirtualListVersion1DataSource
|
||||
/// </summary>
|
||||
/// <param name="listView"></param>
|
||||
public VirtualListVersion1DataSource(VirtualObjectListView listView)
|
||||
: base(listView) {
|
||||
}
|
||||
|
||||
#region Public properties
|
||||
|
||||
|
||||
@@ -369,14 +369,8 @@ namespace BrightIdeasSoftware.Design
|
||||
/// only have to modify the returned collection of actions, but we have to implement
|
||||
/// the properties and commands that the returned actions use. </para>
|
||||
/// </remarks>
|
||||
private class ListViewActionListAdapter : DesignerActionList
|
||||
private class ListViewActionListAdapter(ObjectListViewDesigner designer, DesignerActionList wrappedList) : DesignerActionList(wrappedList.Component)
|
||||
{
|
||||
public ListViewActionListAdapter(ObjectListViewDesigner designer, DesignerActionList wrappedList)
|
||||
: base(wrappedList.Component) {
|
||||
this.designer = designer;
|
||||
this.wrappedList = wrappedList;
|
||||
}
|
||||
|
||||
public override DesignerActionItemCollection GetSortedActionItems() {
|
||||
DesignerActionItemCollection items = wrappedList.GetSortedActionItems();
|
||||
items.RemoveAt(2); // remove Edit Groups
|
||||
@@ -425,21 +419,16 @@ namespace BrightIdeasSoftware.Design
|
||||
set { SetValue(base.Component, "View", value); }
|
||||
}
|
||||
|
||||
ObjectListViewDesigner designer;
|
||||
DesignerActionList wrappedList;
|
||||
ObjectListViewDesigner designer = designer;
|
||||
DesignerActionList wrappedList = wrappedList;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region DesignerCommandSet
|
||||
|
||||
private class CDDesignerCommandSet : DesignerCommandSet
|
||||
private class CDDesignerCommandSet(ComponentDesigner componentDesigner) : DesignerCommandSet
|
||||
{
|
||||
|
||||
public CDDesignerCommandSet(ComponentDesigner componentDesigner) {
|
||||
this.componentDesigner = componentDesigner;
|
||||
}
|
||||
|
||||
public override ICollection GetCommands(string name) {
|
||||
// Debug.WriteLine("CDDesignerCommandSet.GetCommands:" + name);
|
||||
if (componentDesigner != null) {
|
||||
@@ -453,7 +442,7 @@ namespace BrightIdeasSoftware.Design
|
||||
return base.GetCommands(name);
|
||||
}
|
||||
|
||||
private readonly ComponentDesigner componentDesigner;
|
||||
private readonly ComponentDesigner componentDesigner = componentDesigner;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -463,15 +452,12 @@ namespace BrightIdeasSoftware.Design
|
||||
/// This class works in conjunction with the OLVColumns property to allow OLVColumns
|
||||
/// to be added to the ObjectListView.
|
||||
/// </summary>
|
||||
public class OLVColumnCollectionEditor : System.ComponentModel.Design.CollectionEditor
|
||||
/// <remarks>
|
||||
/// Create a OLVColumnCollectionEditor
|
||||
/// </remarks>
|
||||
/// <param name="t"></param>
|
||||
public class OLVColumnCollectionEditor(Type t) : System.ComponentModel.Design.CollectionEditor(t)
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a OLVColumnCollectionEditor
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
public OLVColumnCollectionEditor(Type t)
|
||||
: base(t) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What type of object does this editor create?
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||
<TargetFramework>net9.0-windows10.0.26100.0</TargetFramework>
|
||||
<Deterministic>false</Deterministic>
|
||||
<RootNamespace>BrightIdeasSoftware</RootNamespace>
|
||||
<AssemblyName>ObjectListView</AssemblyName>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
|
||||
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
|
||||
<NoWarn>$(NoWarn);WFO1000</NoWarn>
|
||||
<EnableWinFormsAnalyzers>false</EnableWinFormsAnalyzers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' == 'x64'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Platform)' == 'ARM64'">
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="CustomDictionary.xml" Link="CustomDictionary.xml" />
|
||||
<Content Include="Resources\clear-filter.png" Link="Resources\clear-filter.png" />
|
||||
@@ -19,7 +25,6 @@
|
||||
<Content Include="Resources\sort-ascending.png" Link="Resources\sort-ascending.png" />
|
||||
<Content Include="Resources\sort-descending.png" Link="Resources\sort-descending.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="CellEditing\" />
|
||||
<Folder Include="DragDrop\" />
|
||||
@@ -30,9 +35,8 @@
|
||||
<Folder Include="Resources\" />
|
||||
<Folder Include="Rendering\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Drawing.Common" Version="9.0.2" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.0" />
|
||||
<PackageReference Include="System.Drawing.Common" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -231,15 +231,12 @@ namespace BrightIdeasSoftware {
|
||||
/// This class provides compatibility for v1 RendererDelegates
|
||||
/// </summary>
|
||||
[ToolboxItem(false)]
|
||||
internal class Version1Renderer : AbstractRenderer {
|
||||
public Version1Renderer(RenderDelegate renderDelegate) {
|
||||
this.RenderDelegate = renderDelegate;
|
||||
}
|
||||
internal class Version1Renderer(RenderDelegate renderDelegate) : AbstractRenderer {
|
||||
|
||||
/// <summary>
|
||||
/// The renderer delegate that this renderer wraps
|
||||
/// </summary>
|
||||
public RenderDelegate RenderDelegate;
|
||||
public RenderDelegate RenderDelegate = renderDelegate;
|
||||
|
||||
#region IRenderer Members
|
||||
|
||||
@@ -518,7 +515,7 @@ namespace BrightIdeasSoftware {
|
||||
[Browsable(false),
|
||||
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public ImageList ImageListOrDefault {
|
||||
get { return this.ImageList ?? this.ListView.SmallImageList; }
|
||||
get { return this.ImageList ?? this.ListView.GetSmallImageList(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -809,7 +806,7 @@ namespace BrightIdeasSoftware {
|
||||
/// <param name="g"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual Size CalculatePrimaryCheckBoxSize(Graphics g) {
|
||||
if (!this.ListView.CheckBoxes || !this.ColumnIsPrimary)
|
||||
if (!this.ListView.GetCheckBoxes() || !this.ColumnIsPrimary)
|
||||
return Size.Empty;
|
||||
|
||||
Size size = this.CalculateCheckBoxSize(g);
|
||||
@@ -1299,7 +1296,7 @@ namespace BrightIdeasSoftware {
|
||||
int width = 0;
|
||||
|
||||
// Did they hit a check box on the primary column?
|
||||
if (this.ColumnIsPrimary && this.ListView.CheckBoxes) {
|
||||
if (this.ColumnIsPrimary && this.ListView.GetCheckBoxes()) {
|
||||
Size checkBoxSize = this.CalculateCheckBoxSize(g);
|
||||
int checkBoxTop = this.AlignVertically(r, checkBoxSize.Height);
|
||||
Rectangle r3 = new Rectangle(r.X, checkBoxTop, checkBoxSize.Width, checkBoxSize.Height);
|
||||
@@ -1635,7 +1632,7 @@ namespace BrightIdeasSoftware {
|
||||
/// <param name="r">Bounds of the cell</param>
|
||||
protected virtual void DrawImageAndText(Graphics g, Rectangle r) {
|
||||
int offset = 0;
|
||||
if (this.ListView.CheckBoxes && this.ColumnIsPrimary) {
|
||||
if (this.ListView.GetCheckBoxes() && this.ColumnIsPrimary) {
|
||||
offset = this.DrawCheckBox(g, r) + 6;
|
||||
r.X += offset;
|
||||
r.Width -= offset;
|
||||
|
||||
@@ -51,17 +51,20 @@
|
||||
* If you wish to use this code in a closed source application, please contact phillip.piper@gmail.com.
|
||||
*/
|
||||
|
||||
using BrightIdeasSoftware.Properties;
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
using System.Drawing.Drawing2D;
|
||||
using BrightIdeasSoftware.Properties;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Permissions;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
/// <summary>
|
||||
/// Class used to capture window messages for the header of the list view
|
||||
/// control.
|
||||
|
||||
@@ -40,11 +40,13 @@ using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Permissions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BrightIdeasSoftware
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
/// <summary>
|
||||
/// A limited wrapper around a Windows tooltip window.
|
||||
/// </summary>
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace BrightIdeasSoftware
|
||||
// ReSharper restore DoNotCallOverridableMethodsInConstructor
|
||||
|
||||
// This improves hit detection even if we don't have any state image
|
||||
this.SmallImageList = new ImageList();
|
||||
this.SetSmallImageList(new ImageList());
|
||||
// this.StateImageList.ImageSize = new Size(6, 6);
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace BrightIdeasSoftware
|
||||
return;
|
||||
|
||||
this.hierarchicalCheckboxes = value;
|
||||
this.CheckBoxes = value;
|
||||
this.SetCheckBoxes(value);
|
||||
if (value)
|
||||
this.TriStateCheckBoxes = false;
|
||||
}
|
||||
@@ -2180,15 +2180,12 @@ namespace BrightIdeasSoftware
|
||||
/// <summary>
|
||||
/// This class sorts branches according to how their respective model objects are sorted
|
||||
/// </summary>
|
||||
public class BranchComparer : IComparer<Branch>
|
||||
/// <remarks>
|
||||
/// Create a BranchComparer
|
||||
/// </remarks>
|
||||
/// <param name="actualComparer"></param>
|
||||
public class BranchComparer(IComparer actualComparer) : IComparer<Branch>
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a BranchComparer
|
||||
/// </summary>
|
||||
/// <param name="actualComparer"></param>
|
||||
public BranchComparer(IComparer actualComparer) {
|
||||
this.actualComparer = actualComparer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Order the two branches
|
||||
@@ -2200,7 +2197,7 @@ namespace BrightIdeasSoftware
|
||||
return this.actualComparer.Compare(x.Model, y.Model);
|
||||
}
|
||||
|
||||
private readonly IComparer actualComparer;
|
||||
private readonly IComparer actualComparer = actualComparer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace BrightIdeasSoftware
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.objectListView1.CellEditActivation = BrightIdeasSoftware.ObjectListView.CellEditActivateMode.SingleClick;
|
||||
this.objectListView1.CheckBoxes = true;
|
||||
this.objectListView1.SetCheckBoxes(true);
|
||||
this.objectListView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.olvColumn1});
|
||||
this.objectListView1.FullRowSelect = true;
|
||||
|
||||
@@ -233,13 +233,9 @@ namespace BrightIdeasSoftware
|
||||
/// A Comparer that will sort a list of columns so that visible ones come before hidden ones,
|
||||
/// and that are ordered by their display order.
|
||||
/// </summary>
|
||||
private class SortByDisplayOrder : IComparer<OLVColumn>
|
||||
private class SortByDisplayOrder(ColumnSelectionForm form) : IComparer<OLVColumn>
|
||||
{
|
||||
public SortByDisplayOrder(ColumnSelectionForm form)
|
||||
{
|
||||
this.Form = form;
|
||||
}
|
||||
private ColumnSelectionForm Form;
|
||||
private ColumnSelectionForm Form = form;
|
||||
|
||||
#region IComparer<OLVColumn> Members
|
||||
|
||||
|
||||
@@ -72,15 +72,12 @@ namespace BrightIdeasSoftware
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public class TypedObjectListView<T> where T : class
|
||||
/// <remarks>
|
||||
/// Create a typed wrapper around the given list.
|
||||
/// </remarks>
|
||||
/// <param name="olv">The listview to be wrapped</param>
|
||||
public class TypedObjectListView<T>(ObjectListView olv) where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a typed wrapper around the given list.
|
||||
/// </summary>
|
||||
/// <param name="olv">The listview to be wrapped</param>
|
||||
public TypedObjectListView(ObjectListView olv) {
|
||||
this.olv = olv;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Properties
|
||||
@@ -115,7 +112,7 @@ namespace BrightIdeasSoftware
|
||||
get { return olv; }
|
||||
set { olv = value; }
|
||||
}
|
||||
private ObjectListView olv;
|
||||
private ObjectListView olv = olv;
|
||||
|
||||
/// <summary>
|
||||
/// Get or set the list of all model objects
|
||||
@@ -325,16 +322,13 @@ namespace BrightIdeasSoftware
|
||||
/// A type-safe wrapper around an OLVColumn
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class TypedColumn<T> where T : class
|
||||
/// <remarks>
|
||||
/// Creates a TypedColumn
|
||||
/// </remarks>
|
||||
/// <param name="column"></param>
|
||||
public class TypedColumn<T>(OLVColumn column) where T : class
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a TypedColumn
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
public TypedColumn(OLVColumn column) {
|
||||
this.column = column;
|
||||
}
|
||||
private OLVColumn column;
|
||||
private OLVColumn column = column;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
||||
@@ -175,7 +175,7 @@ namespace BrightIdeasSoftware
|
||||
public override IList CheckedObjects {
|
||||
get {
|
||||
// If we aren't should checkboxes, then no objects can be checked
|
||||
if (!this.CheckBoxes)
|
||||
if (!this.GetCheckBoxes())
|
||||
return new ArrayList();
|
||||
|
||||
// If the data source has somehow vanished, we can't do anything
|
||||
@@ -199,7 +199,7 @@ namespace BrightIdeasSoftware
|
||||
return objects;
|
||||
}
|
||||
set {
|
||||
if (!this.CheckBoxes)
|
||||
if (!this.GetCheckBoxes())
|
||||
return;
|
||||
|
||||
// If a custom check state getter is install, we can't use our check state management
|
||||
|
||||
16
README.md
16
README.md
@@ -1,6 +1,3 @@
|
||||
**NOTICE: This project currently transited to a new maintainer. Development help would be greatly appreciated.**
|
||||
|
||||
<br/><br/>
|
||||
<p align="center">
|
||||
<img width="450" src="https://github.com/mRemoteNG/mRemoteNG/blob/mRemoteNGProjectFiles/Header_dark.png">
|
||||
</p>
|
||||
@@ -28,9 +25,6 @@
|
||||
<a href="https://www.paypal.com/paypalme/mremoteng">
|
||||
<img alt="PayPal" src="https://img.shields.io/badge/%24-PayPal-blue.svg?label=Donate&logo=PayPal&style=flat-square">
|
||||
</a>
|
||||
<a href="bitcoin:16fUnHUM3k7W9Fvpc6dug7TAdfeGEcLbSg">
|
||||
<img alt="Bitcoin" src="https://img.shields.io/badge/%24-Bitcoin.svg?label=Donate&logo=bitcoin&style=flat-square">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -54,7 +48,7 @@
|
||||
| ---------------|--------------|-----------|
|
||||
| Stable |  | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.76.20) |
|
||||
| Preview |  | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.77.1) |
|
||||
| Nightly |  | [](https://github.com/mRemoteNG/mRemoteNG/releases/tag/2023.03.03-v1.77.3-nb) |
|
||||
| Nightly |  | [/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/20250916-v1.78.2-NB-(3177)) |
|
||||
|
||||
## Features
|
||||
|
||||
@@ -90,10 +84,9 @@ You will need to compile it yourself using Visual Studio.
|
||||
|
||||
### Minimum Requirements
|
||||
|
||||
* [Microsoft Visual C++ Redistributable for Visual Studio 2015 - 2022](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads)
|
||||
* [Microsoft .NET 6.0 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/6.0)
|
||||
* Microsoft Terminal Service Client 6.0 or later
|
||||
* Needed if you use RDP. mstscax.dll and/or msrdp.ocx be registered.
|
||||
* [Microsoft .NET Desktop Runtime 9.0](https://dotnet.microsoft.com/download/dotnet/6.0)
|
||||
* [Microsoft Visual C++ Redistributable x86 (note: use 32-bit, required until #2870 is resolved)](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-supported-redistributable-version)
|
||||
* Microsoft Terminal Service Client 6.0 or later (needed if you use RDP with mstscax.dll and/or msrdp.ocx to be registered)
|
||||
|
||||
### Download
|
||||
|
||||
@@ -137,6 +130,7 @@ _If you are using the Portable version, simply deleting the folder that contains
|
||||
|
||||
* [PSmRemoteNG](https://github.com/realslacker/PSmRemoteNG) A module to create mRemoteNG connection files from PowerShell.
|
||||
* [mRemoteNGOpenVPN](https://github.com/T3los/mRemoteNGOpenVPN) A script that can be embedded as an external tool to control OpenVPN.
|
||||
* [mRemoteNG-Icons](https://github.com/bearlikelion/mRemoteNG-Icons) A collection of fancy icons to customize the connections
|
||||
|
||||
## Contribute
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
U2FsdGVkX1/uEeToOEIrunpoPNl7NUYNQfI+ixMzGgKX0DlHZxa/PonAVd9NoAE+
|
||||
dqWegkN8fa/M2HcW8moN5sN0yS88amG8cfwRZNRSgRB4IxDdYPjM/iX7y8FjUh9R
|
||||
OZnGhq1rAkqcf7ASAdZfQDSFOAEDPQgByN4IB2j/G3ueqV3jf5sWWiM0ielcorWX
|
||||
jXuEL7uIk9diI3Qh3BVqmrotzErzqTTLB4DWoL1aWqRRYH+exKahfcMT3C9r+tul
|
||||
ETH6o1im3kdYzFgHl58FmihbHa+h1+c+DWVGGXRxJPw1DZfg8/+ldIy8J75aWimz
|
||||
2MX+PiBVQj+wYlSSkQLj2EdbpSERlinE1O55ldwpbnMPAlYCgFRdO3/hiB6LiLLt
|
||||
n9s8f32HLNG20Mk1oxXdN9VPOw+RwQpUf6Zfcyps6e/9EFKBLnwq4cYwM/dHRuez
|
||||
w48EJX5wKzpukHn2UFg5aCRGYU/4NyUn+AlIjjCMBWY1R0uBhC340cl6YqoPFN12
|
||||
clzbS6JdQS+ktusCeaKcsj2iknVqQrGY81LKrTaQZdfehGwAn9pMWE3iWRX80yzO
|
||||
s08lpmHfPK4uhtlyIbdReLn4n7hvB8KRVa7Foms+4wpEwKrL8KF/8CYc89Tm3PSD
|
||||
LCrLr7rzCHh51ncJXHAwZqY2ZRLnQBVwhIRsFYyZ595b89tuDY00sYpWnTKzWubK
|
||||
UD993CmYKg1cA+mj6NR6iSmecawsUz68nI/nmHM2APE5cCCHSK3lz40e9Z9Hmy5Y
|
||||
kVS6c86a+gwNyn4F9t3iISdj2vIOwGMVWQLeY+nwpiKnnOuI0XPtIMjNbhoaDToT
|
||||
kph2ZVjqbpmYHgTSX71v8Y16Stl+p/dZn0dE2d4JhxOJxDN//H6y7mOwg8DYX9GP
|
||||
rFBMIEWyEQyEFYTmWgztQ5KU89w0lV1qiWpaiWR/IDkGbUzHR8ELp4NHYPbZnuYa
|
||||
FFXooJGPsQ02ioXPm18Lkhloo63lANgyBE0jc1x9hPrI0oVn1wTkKdeW13IbHzrn
|
||||
VsGXeZz06bB46QChXUPmQ49sNkAXcMDnfNFM9ayUa8eVmNx9fWabtBy8qs7rpdv0
|
||||
1y/2ud4Da9t7SAUvxwI65+b2Ytk05pLFLmQYb01g4BpBDxbJW3yw3CqKgMnLoZ3t
|
||||
s2kiUpn7FEQU8jbpbFV+UB4DdJgm8S7o1gbTEWYTscZ7l+oLCmQgMYoi/EJDDIa2
|
||||
cCSdGy4p7kLlLUoO438Mz36+FDf6qX2B86ezVdNnXQb3UPljjDxiOFM6NkI3HTpl
|
||||
RqxjBg8JdrwoQ1UMha6ucDKhPXq1xkg0dpO9QyjxywssG3krgQ5Py64s5Xu7IgQm
|
||||
AzmwGTZ6gFZlDTr9SpJkiucF9vexCo6JHHkF8OjhS49FanqB8otJvg5JclVugP51
|
||||
LcqqvuMkAsFago261SNcOhgtR6nV5B9QgHyr66c6YnTlwt07T1Qq3S1lw2x0Eccs
|
||||
PKbJDVU5rAHiM71QYmwsuoC8qkYPTtVPIoUTs+5u5aLywVoLejr1dE5twNXy5PYY
|
||||
fDwubg0YG3kchvv85N3epZ1h50ADq3W3msU9bWDKWwdwIbpGq+dwjkLssBQmjVtI
|
||||
R8rGbt1DgL7xtRNF9ESnWVkfHJvJu/5oD6wGAU/oIfBxVON0VYb1evc8wRdQTbDH
|
||||
Dnt+aKwcSPYdyGVRKfRtBGvEZ8rB5hzCXQnS795L0imdfXjBSJn7Pnl9VwpcB3Pr
|
||||
aZ6s0GcB8kYDEXzjv+o7JF6k5i2I+sVGwvFVGIoVd/Igq2ysrk/GfWVov0SUu78A
|
||||
JeHYdtRuKwXOdZw2cjZQ72bvFaHOuoXrQnyKyZDWRyu0NB5HLW75v/YEbr4msIm9
|
||||
E+3HFwRvKSTfUx/M4NgVKrgsHDeBRD4tLNx/SerQvqaplunM7OfAtULucveUhwSo
|
||||
vT6uNK3URe1qDgX554cz8c6+KrkglTLFMuKfNWj3q/uSM0BxTTD9QgorNdlMmErH
|
||||
TfV/ZpZACpuMFRbC5xQRkCG1x4U12pdPbtIkGtVBJROEXhP1aw3BDWwrIN7zSgfj
|
||||
8I4OF4fbj/rSuvI4klzi1zlUMQQnenlRURE+7DKRxtWipJhW9vtDI0LXN7gGfmbR
|
||||
73uR3YUny6zUJ0svqaWj4Eo6t3g99nmk4D2hm/622dRksv2HqEQiq29jJxlcbdZB
|
||||
PU96wOp54s/BzgodyI5dh+xL06Obr9AltLV9vw3iK0VBZqquj9FuhvWC1tYlZQJF
|
||||
AOgVDOGUZzmAJXftI7gaohFBwsT5tAHQtBuY7tB3b1hrnfrFb9FTNxGZJKcIH3p4
|
||||
dOAvedsfuq+2/lU9iM4tX9fjSzfnGRZRuKCGDSdhE6EDik9/f2kSCoY9z0zJwdZH
|
||||
324TpGbZNbgcwgHDL9i5Nsnaua5yxtr0/Fr1We1tvn0=
|
||||
@@ -5,76 +5,60 @@ VisualStudioVersion = 17.0.31912.275
|
||||
MinimumVisualStudioVersion = 14.0.25420.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNG", "mRemoteNG\mRemoteNG.csproj", "{4934A491-40BC-4E5B-9166-EA1169A220F6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNGTests", "mRemoteNGTests\mRemoteNGTests.csproj", "{1453B37F-8621-499E-B0B2-6091F76DC0BB}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "mRemoteNGInstaller", "mRemoteNGInstaller", "{4FE795BE-646E-4F1B-BAD0-A68EA26394DD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomActions", "mRemoteNGInstaller\CustomActions\CustomActions.csproj", "{5423D985-CB48-4344-B47F-E8C6D60C8B04}"
|
||||
EndProject
|
||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Installer", "mRemoteNGInstaller\Installer\Installer.wixproj", "{F0168B9F-6815-40DF-BA53-46CEE7683B68}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6} = {4934A491-40BC-4E5B-9166-EA1169A220F6}
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04} = {5423D985-CB48-4344-B47F-E8C6D60C8B04}
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD} = {A56A2029-79B8-492A-ABE5-D2BFE05801BD}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mRemoteNGSpecs", "mRemoteNGSpecs\mRemoteNGSpecs.csproj", "{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExternalConnectors", "ExternalConnectors\ExternalConnectors.csproj", "{A56A2029-79B8-492A-ABE5-D2BFE05801BD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectListView.NetCore", "ObjectListView\ObjectListView.NetCore.csproj", "{5718734C-03AC-4954-89B1-1723CF03AF10}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|arm64 = Debug|arm64
|
||||
Debug|x64 = Debug|x64
|
||||
Release Installer and Portable|arm64 = Release Installer and Portable|arm64
|
||||
Release Installer and Portable|x64 = Release Installer and Portable|x64
|
||||
Release|arm64 = Release|arm64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|arm64.Build.0 = Debug|arm64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x64.Build.0 = Debug|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|arm64.ActiveCfg = Release Portable|arm64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|arm64.Build.0 = Release Portable|arm64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|x64.ActiveCfg = Release Portable|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer and Portable|x64.Build.0 = Release Portable|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|arm64.ActiveCfg = Release|arm64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|arm64.Build.0 = Release|arm64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x64.ActiveCfg = Release|x64
|
||||
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x64.Build.0 = Release|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer and Portable|x64.ActiveCfg = Release Portable|x64
|
||||
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x64.Build.0 = Debug|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer and Portable|x64.Build.0 = Release|x64
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x64.ActiveCfg = Release|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x64.Build.0 = Debug|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer and Portable|x64.ActiveCfg = Release|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer and Portable|x64.Build.0 = Release|x64
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|x64.ActiveCfg = Release|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Debug|x64.Build.0 = Debug|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release Installer and Portable|x64.ActiveCfg = Release Installer|x64
|
||||
{16AA21E2-D6B7-427D-AB7D-AA8C611B724E}.Release|x64.ActiveCfg = Release|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|arm64.Build.0 = Debug|arm64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Debug|x64.Build.0 = Debug|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|arm64.ActiveCfg = Release Portable|arm64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|arm64.Build.0 = Release Portable|arm64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|x64.ActiveCfg = Release Portable|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release Installer and Portable|x64.Build.0 = Release Portable|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|arm64.ActiveCfg = Release|arm64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|arm64.Build.0 = Release|arm64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|x64.ActiveCfg = Release|x64
|
||||
{A56A2029-79B8-492A-ABE5-D2BFE05801BD}.Release|x64.Build.0 = Release|x64
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Debug|arm64.ActiveCfg = Debug|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Debug|arm64.Build.0 = Debug|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release Installer and Portable|arm64.ActiveCfg = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release Installer and Portable|arm64.Build.0 = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release Installer and Portable|x64.ActiveCfg = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release Installer and Portable|x64.Build.0 = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release|arm64.ActiveCfg = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release|arm64.Build.0 = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{5718734C-03AC-4954-89B1-1723CF03AF10}.Release|x64.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{5423D985-CB48-4344-B47F-E8C6D60C8B04} = {4FE795BE-646E-4F1B-BAD0-A68EA26394DD}
|
||||
{F0168B9F-6815-40DF-BA53-46CEE7683B68} = {4FE795BE-646E-4F1B-BAD0-A68EA26394DD}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5D390A0C-2FC4-4908-B86E-7E4DEF5916EC}
|
||||
EndGlobalSection
|
||||
|
||||
124
mRemoteNG/App/Checks/DotNetRuntimeCheck.cs
Normal file
124
mRemoteNG/App/Checks/DotNetRuntimeCheck.cs
Normal file
@@ -0,0 +1,124 @@
|
||||
using Microsoft.Win32;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace mRemoteNG.DotNet.Update
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class DotNetRuntimeCheck
|
||||
{
|
||||
public const string RequiredDotnetVersion = "9.0";
|
||||
private const string ReleaseFeedUrl = "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/releases-index.json";
|
||||
|
||||
#region Installed Version Check
|
||||
/// <summary>
|
||||
/// Gets the installed .NET 9 runtime version if present
|
||||
/// </summary>
|
||||
/// <returns>The version string (e.g., "v9.0.0") or null if not found</returns>
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static string? GetLatestDotNetRuntimeVersion()
|
||||
{
|
||||
string[] registryPaths = new[]
|
||||
{
|
||||
@"SOFTWARE\dotnet\Setup\InstalledVersions\x86",
|
||||
@"SOFTWARE\dotnet\Setup\InstalledVersions\x64",
|
||||
@"SOFTWARE\dotnet\Setup\InstalledVersions\arm64"
|
||||
};
|
||||
|
||||
foreach (string path in registryPaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
using RegistryKey? key = Registry.LocalMachine.OpenSubKey(path);
|
||||
if (key == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for the "sharedhost" subkey
|
||||
using (RegistryKey? sharedHostKey = key.OpenSubKey("sharedhost"))
|
||||
{
|
||||
if (sharedHostKey == null) {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Look for the "Version" value in sharedhost
|
||||
object? versionValue = sharedHostKey.GetValue("Version");
|
||||
if (versionValue != null)
|
||||
{
|
||||
string? version = versionValue.ToString();
|
||||
if (!string.IsNullOrWhiteSpace(version))
|
||||
{
|
||||
return version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error checking registry fallback: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion Installed Version Check
|
||||
#region Latest Online Version Check
|
||||
public static async Task<(string latestRuntimeVersion, string downloadUrl)> GetLatestAvailableDotNetVersionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var httpClient = new HttpClient();
|
||||
httpClient.DefaultRequestHeaders.Add("User-Agent", "DotNetRuntimeChecker");
|
||||
|
||||
string jsonContent = await httpClient.GetStringAsync(ReleaseFeedUrl);
|
||||
JObject releasesIndex = JObject.Parse(jsonContent);
|
||||
|
||||
// Find the entry for .NET matching RequiredDotnetVersion
|
||||
JToken? dotnetEntry = releasesIndex["releases-index"]?.FirstOrDefault(entry => entry["channel-version"]?.ToString() == RequiredDotnetVersion);
|
||||
|
||||
if (dotnetEntry != null && dotnetEntry["latest-runtime"] != null)
|
||||
{
|
||||
string? latestRuntimeVersion = dotnetEntry["latest-runtime"]?.ToString();
|
||||
string arch;
|
||||
switch (RuntimeInformation.OSArchitecture)
|
||||
{
|
||||
case Architecture.Arm64:
|
||||
arch = "arm64";
|
||||
break;
|
||||
case Architecture.X86:
|
||||
arch = "x86";
|
||||
break;
|
||||
case Architecture.X64:
|
||||
arch = "x64";
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException($"Unsupported architecture: {RuntimeInformation.OSArchitecture}");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(latestRuntimeVersion))
|
||||
{
|
||||
// Construct the download URL using the latest version
|
||||
string downloadUrl = $"https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-{latestRuntimeVersion}-windows-{arch}-installer";
|
||||
return (latestRuntimeVersion, downloadUrl);
|
||||
}
|
||||
}
|
||||
|
||||
return ("Unknown", "");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error fetching latest version: {ex.Message}");
|
||||
return ("Unknown", "");
|
||||
}
|
||||
}
|
||||
#endregion Latest Online Version Check
|
||||
}
|
||||
}
|
||||
26
mRemoteNG/App/Checks/InternetConnection.cs
Normal file
26
mRemoteNG/App/Checks/InternetConnection.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace mRemoteNG.App.Update
|
||||
{
|
||||
public class InternetConnection
|
||||
{
|
||||
public static bool IsPosible()
|
||||
{
|
||||
try
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
client.Timeout = TimeSpan.FromSeconds(5);
|
||||
return client.GetAsync("https://www.microsoft.com").Result.IsSuccessStatusCode;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
mRemoteNG/App/Checks/VCppRuntimeCheck.cs
Normal file
42
mRemoteNG/App/Checks/VCppRuntimeCheck.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Versioning; // Add for SupportedOSPlatform
|
||||
|
||||
namespace mRemoteNG.App.Update
|
||||
{
|
||||
public class VCppRuntimeCheck
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static List<string> GetInstalledVcRedistVersions()
|
||||
{
|
||||
var installedVersions = new List<string>();
|
||||
var baseKeys = new[]
|
||||
{
|
||||
@"SOFTWARE\Microsoft\VisualStudio",
|
||||
@"SOFTWARE\WOW6432Node\Microsoft\VisualStudio"
|
||||
};
|
||||
|
||||
for (int major = 14; major <= 17; major++) // Covers 2015–2022+
|
||||
{
|
||||
for (int minor = 0; minor <= 3; minor++)
|
||||
{
|
||||
string version = $"{major}.{minor}";
|
||||
foreach (var baseKey in baseKeys)
|
||||
{
|
||||
string path = $@"{baseKey}\{version}\VC\Runtimes\x64";
|
||||
using (RegistryKey? key = Registry.LocalMachine.OpenSubKey(path))
|
||||
{
|
||||
if (key?.GetValue("Installed") is int installed && installed == 1)
|
||||
{
|
||||
installedVersions.Add(version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return installedVersions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,11 @@ namespace mRemoteNG.App.Info
|
||||
|
||||
public static Version GetApplicationVersion()
|
||||
{
|
||||
_ = System.Version.TryParse(ApplicationVersion, out Version v);
|
||||
return v;
|
||||
string cleanedVersion = ApplicationVersion.Split(' ')[0].Replace("(", "").Replace(")", "").Replace("Build", "");
|
||||
cleanedVersion = cleanedVersion + "." + ApplicationVersion.Split(' ')[^1].Replace(")", "");
|
||||
|
||||
_ = System.Version.TryParse(cleanedVersion, out Version parsedVersion);
|
||||
return parsedVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,9 @@ using mRemoteNG.Resources.Language;
|
||||
namespace mRemoteNG.App.Initialization
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class StartupDataLogger
|
||||
public class StartupDataLogger(MessageCollector messageCollector)
|
||||
{
|
||||
private readonly MessageCollector _messageCollector;
|
||||
|
||||
public StartupDataLogger(MessageCollector messageCollector)
|
||||
{
|
||||
_messageCollector = messageCollector ?? throw new ArgumentNullException(nameof(messageCollector));
|
||||
}
|
||||
private readonly MessageCollector _messageCollector = messageCollector ?? throw new ArgumentNullException(nameof(messageCollector));
|
||||
|
||||
public void LogStartupData()
|
||||
{
|
||||
|
||||
@@ -1,101 +1,158 @@
|
||||
using System;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
using mRemoteNG.App.Update;
|
||||
using mRemoteNG.Config.Settings;
|
||||
using mRemoteNG.DotNet.Update;
|
||||
using mRemoteNG.DotNet.Update;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using mRemoteNG.Config.Settings;
|
||||
using mRemoteNG.UI.Forms;
|
||||
|
||||
|
||||
|
||||
namespace mRemoteNG.App
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static class ProgramRoot
|
||||
{
|
||||
private static Mutex _mutex;
|
||||
private static Mutex? _mutex;
|
||||
private static FrmSplashScreenNew _frmSplashScreen = null;
|
||||
private static string customResourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Languages");
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
private static System.Threading.Thread? _wpfSplashThread;
|
||||
private static FrmSplashScreenNew? _wpfSplash;
|
||||
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Trace.WriteLine("!!!!!!=============== TEST ==================!!!!!!!!!!!!!");
|
||||
// Forcing to load System.Configuration.ConfigurationManager before any other assembly to be able to check settings
|
||||
try
|
||||
{
|
||||
string assemblyFile = "System.Configuration.ConfigurationManager" + ".dll";
|
||||
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
|
||||
// Ensure the real entry point is definitely STA
|
||||
MainAsync(args).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
|
||||
if (File.Exists(assemblyPath))
|
||||
{
|
||||
Assembly.LoadFrom(assemblyPath);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
Trace.WriteLine("Error occured: " + ex.Message);
|
||||
}
|
||||
|
||||
//Subscribe to AssemblyResolve event
|
||||
private static Task MainAsync(string[] args)
|
||||
{
|
||||
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
|
||||
|
||||
//Check if local settings DB exist or accessible
|
||||
CheckLockalDB();
|
||||
string? installedVersion = DotNetRuntimeCheck.GetLatestDotNetRuntimeVersion();
|
||||
//installedVersion = ""; // Force check for testing purposes
|
||||
|
||||
Lazy<bool> singleInstanceOption = new Lazy<bool>(() => Properties.OptionsStartupExitPage.Default.SingleInstance);
|
||||
var checkFail = false;
|
||||
|
||||
// Checking .NET Runtime version
|
||||
var (latestRuntimeVersion, downloadUrl) = DotNetRuntimeCheck.GetLatestAvailableDotNetVersionAsync().GetAwaiter().GetResult();
|
||||
if (string.IsNullOrEmpty(installedVersion))
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
$".NET Desktop Runtime at least {DotNetRuntimeCheck.RequiredDotnetVersion}.0 is required.\n" +
|
||||
"The application will now exit.\n\nPlease download and install latest desktop runtime:\n" + downloadUrl,
|
||||
"Missing .NET " + DotNetRuntimeCheck.RequiredDotnetVersion + " Runtime",
|
||||
MessageBoxButtons.OKCancel,
|
||||
MessageBoxIcon.Information);
|
||||
|
||||
if (result == DialogResult.OK && InternetConnection.IsPosible())
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(fileName: downloadUrl) { UseShellExecute = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Unable to open download link: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
checkFail = true;
|
||||
}
|
||||
|
||||
// Checking Visual C++ Redistributable version
|
||||
if (VCppRuntimeCheck.GetInstalledVcRedistVersions() == null || VCppRuntimeCheck.GetInstalledVcRedistVersions().Count == 0)
|
||||
{
|
||||
var downloadUrl2 = "https://aka.ms/vs/17/release/vc_redist.x64.exe";
|
||||
try
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
$"A Visual C++ (MSVC) runtime library is required.\n" +
|
||||
"The application will now exit.\n\nPlease download and install latest desktop runtime:\n" + downloadUrl2,
|
||||
"Missing Visual C++ Redistributable x86 Runtime",
|
||||
MessageBoxButtons.OKCancel,
|
||||
MessageBoxIcon.Information);
|
||||
|
||||
if (result == DialogResult.OK && InternetConnection.IsPosible())
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(fileName: downloadUrl2) { UseShellExecute = true });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Unable to open download link: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
checkFail = true;
|
||||
}
|
||||
|
||||
if (checkFail)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
Lazy<bool> singleInstanceOption = new(() => Properties.OptionsStartupExitPage.Default.SingleInstance);
|
||||
if (singleInstanceOption.Value)
|
||||
{
|
||||
StartApplicationAsSingleInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
StartApplication();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
// Assembly resolve handler
|
||||
private static Assembly? OnAssemblyResolve(object? sender, ResolveEventArgs args)
|
||||
{
|
||||
try
|
||||
{
|
||||
string assemblyName = new AssemblyName(args.Name).Name ?? string.Empty;
|
||||
if (assemblyName.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
|
||||
return null;
|
||||
|
||||
string assemblyFile = assemblyName + ".dll";
|
||||
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
|
||||
|
||||
if (File.Exists(assemblyPath))
|
||||
return Assembly.LoadFrom(assemblyPath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Suppress resolution exceptions; return null to continue standard probing
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void CheckLockalDB()
|
||||
{
|
||||
LocalSettingsDBManager settingsManager = new LocalSettingsDBManager(dbPath: "mRemoteNG.appSettings", useEncryption: false, schemaFilePath: "");
|
||||
LocalDBManager settingsManager = new LocalDBManager(dbPath: "mRemoteNG.appSettings", useEncryption: false, schemaFilePath: "");
|
||||
}
|
||||
private static Assembly OnAssemblyResolve(object sender, ResolveEventArgs resolveArgs)
|
||||
{
|
||||
string assemblyName = new AssemblyName(resolveArgs.Name).Name.Replace(".resources", string.Empty);
|
||||
string assemblyFile = assemblyName + ".dll";
|
||||
string assemblyPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assemblies", assemblyFile);
|
||||
|
||||
|
||||
if (File.Exists(assemblyPath))
|
||||
{
|
||||
return Assembly.LoadFrom(assemblyPath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void StartApplication()
|
||||
{
|
||||
CatchAllUnhandledExceptions();
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
_frmSplashScreen = FrmSplashScreenNew.GetInstance();
|
||||
|
||||
Screen targetScreen = Screen.PrimaryScreen;
|
||||
|
||||
Rectangle viewport = targetScreen.WorkingArea;
|
||||
_frmSplashScreen.Top = viewport.Top;
|
||||
_frmSplashScreen.Left = viewport.Left;
|
||||
// normally it should be screens[1] however due DPI apply 1 size "same" as default with 100%
|
||||
_frmSplashScreen.Left = viewport.Left + (targetScreen.Bounds.Size.Width - _frmSplashScreen.Width) / 2;
|
||||
_frmSplashScreen.Top = viewport.Top + (targetScreen.Bounds.Size.Height - _frmSplashScreen.Height) / 2;
|
||||
_frmSplashScreen.ShowInTaskbar = false;
|
||||
_frmSplashScreen.Show();
|
||||
ShowSplashOnStaThread();
|
||||
|
||||
Application.Run(FrmMain.Default);
|
||||
}
|
||||
@@ -134,8 +191,24 @@ namespace mRemoteNG.App
|
||||
Process currentProcess = Process.GetCurrentProcess();
|
||||
foreach (Process enumeratedProcess in Process.GetProcessesByName(currentProcess.ProcessName))
|
||||
{
|
||||
// Safely check for null MainModule and FileName
|
||||
string? enumeratedFileName = null;
|
||||
string? currentFileName = null;
|
||||
try
|
||||
{
|
||||
enumeratedFileName = enumeratedProcess.MainModule?.FileName;
|
||||
currentFileName = currentProcess.MainModule?.FileName;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Access to MainModule can throw exceptions for some processes; ignore and continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (enumeratedProcess.Id != currentProcess.Id &&
|
||||
enumeratedProcess.MainModule.FileName == currentProcess.MainModule.FileName &&
|
||||
!string.IsNullOrEmpty(enumeratedFileName) &&
|
||||
!string.IsNullOrEmpty(currentFileName) &&
|
||||
enumeratedFileName == currentFileName &&
|
||||
enumeratedProcess.MainWindowHandle != IntPtr.Zero)
|
||||
windowHandle = enumeratedProcess.MainWindowHandle;
|
||||
}
|
||||
@@ -145,31 +218,56 @@ namespace mRemoteNG.App
|
||||
|
||||
private static void CatchAllUnhandledExceptions()
|
||||
{
|
||||
System.Windows.Forms.Application.ThreadException += ApplicationOnThreadException;
|
||||
System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
Application.ThreadException += ApplicationOnThreadException;
|
||||
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
|
||||
}
|
||||
|
||||
private static void ApplicationOnThreadException(object sender, ThreadExceptionEventArgs e)
|
||||
{
|
||||
// if (PresentationSource.FromVisual(FrmSplashScreenNew))
|
||||
FrmSplashScreenNew.GetInstance().Close();
|
||||
|
||||
CloseSplash();
|
||||
if (FrmMain.Default.IsDisposed) return;
|
||||
|
||||
FrmUnhandledException window = new(e.Exception, false);
|
||||
window.ShowDialog(FrmMain.Default);
|
||||
}
|
||||
|
||||
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
//TODO: Check if splash closed properly
|
||||
//if (!FrmSplashScreenNew.GetInstance().IsDisposed)
|
||||
// FrmSplashScreenNew.GetInstance().Close();
|
||||
|
||||
FrmUnhandledException window = new(e.ExceptionObject as Exception, e.IsTerminating);
|
||||
window.ShowDialog(FrmMain.Default);
|
||||
}
|
||||
|
||||
|
||||
private static void ShowSplashOnStaThread()
|
||||
{
|
||||
_wpfSplashThread = new System.Threading.Thread(() =>
|
||||
{
|
||||
_wpfSplash = FrmSplashScreenNew.GetInstance();
|
||||
|
||||
// Center the splash screen on the primary screen before showing it
|
||||
_wpfSplash.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
|
||||
|
||||
_wpfSplash.ShowInTaskbar = false;
|
||||
_wpfSplash.Show();
|
||||
System.Windows.Forms.Integration.ElementHost.EnableModelessKeyboardInterop(_wpfSplash);
|
||||
System.Windows.Threading.Dispatcher.Run(); // WPF message loop
|
||||
})
|
||||
{ IsBackground = true };
|
||||
_wpfSplashThread.SetApartmentState(System.Threading.ApartmentState.STA);
|
||||
_wpfSplashThread.Start();
|
||||
}
|
||||
|
||||
private static void CloseSplash()
|
||||
{
|
||||
if (_wpfSplash != null)
|
||||
{
|
||||
_wpfSplash.Dispatcher.Invoke(() => _wpfSplash.Close());
|
||||
_wpfSplash = null;
|
||||
}
|
||||
if (_wpfSplashThread != null)
|
||||
{
|
||||
_wpfSplashThread.Join();
|
||||
_wpfSplashThread = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,10 +84,8 @@ namespace mRemoteNG.App
|
||||
try
|
||||
{
|
||||
await _appUpdate.GetUpdateInfoAsync();
|
||||
if (_appUpdate.IsUpdateAvailable())
|
||||
{
|
||||
Windows.Show(WindowType.Update);
|
||||
}
|
||||
// Update is available, but don't show the panel automatically at startup
|
||||
// User can check for updates manually via Help > Check for Updates menu
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -26,8 +26,9 @@ namespace mRemoteNG.App
|
||||
|
||||
internal static ConfigWindow ConfigForm { get; set; } = new ConfigWindow();
|
||||
internal static ErrorAndInfoWindow ErrorsForm { get; set; } = new ErrorAndInfoWindow();
|
||||
private static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
|
||||
internal static UpdateWindow UpdateForm { get; set; } = new UpdateWindow();
|
||||
internal static SSHTransferWindow SshtransferForm { get; private set; } = new SSHTransferWindow();
|
||||
internal static OptionsWindow OptionsFormWindow { get; private set; }
|
||||
|
||||
|
||||
public static void Show(WindowType windowType)
|
||||
@@ -44,8 +45,10 @@ namespace mRemoteNG.App
|
||||
_adimportForm.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.Options:
|
||||
FrmMain.OptionsForm.SetActivatedPage(Language.StartupExit);
|
||||
FrmMain.OptionsForm.Visible = true;
|
||||
if (OptionsFormWindow == null || OptionsFormWindow.IsDisposed)
|
||||
OptionsFormWindow = new OptionsWindow();
|
||||
OptionsFormWindow.SetActivatedPage(Language.StartupExit);
|
||||
OptionsFormWindow.Show(dockPanel);
|
||||
break;
|
||||
case WindowType.SSHTransfer:
|
||||
if (SshtransferForm == null || SshtransferForm.IsDisposed)
|
||||
|
||||
@@ -19,22 +19,16 @@ using mRemoteNG.Tree.Root;
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlConnectionsLoader : IConnectionsLoader
|
||||
public class SqlConnectionsLoader(
|
||||
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
|
||||
IDataProvider<string> dataProvider) : IConnectionsLoader
|
||||
{
|
||||
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer;
|
||||
private readonly IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> _localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
|
||||
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
private readonly IDataProvider<string> _dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
|
||||
|
||||
private Func<Optional<SecureString>> AuthenticationRequestor { get; set; } = () => MiscTools.PasswordDialog("", false);
|
||||
|
||||
public SqlConnectionsLoader(
|
||||
IDeserializer<string, IEnumerable<LocalConnectionPropertiesModel>> localConnectionPropertiesDeserializer,
|
||||
IDataProvider<string> dataProvider)
|
||||
{
|
||||
_localConnectionPropertiesDeserializer = localConnectionPropertiesDeserializer.ThrowIfNull(nameof(localConnectionPropertiesDeserializer));
|
||||
_dataProvider = dataProvider.ThrowIfNull(nameof(dataProvider));
|
||||
}
|
||||
|
||||
public ConnectionTreeModel Load()
|
||||
{
|
||||
IDatabaseConnector connector = DatabaseConnectorFactory.DatabaseConnectorFromSettings();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Data.Common;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.App.Info;
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
@@ -23,18 +24,11 @@ using mRemoteNG.Config.Serializers.ConnectionSerializers.Sql;
|
||||
namespace mRemoteNG.Config.Connections
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlConnectionsSaver : ISaver<ConnectionTreeModel>
|
||||
public class SqlConnectionsSaver(SaveFilter saveFilter, ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> localPropertieSerializer, IDataProvider<string> localPropertiesDataProvider) : ISaver<ConnectionTreeModel>
|
||||
{
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer;
|
||||
private readonly IDataProvider<string> _dataProvider;
|
||||
|
||||
public SqlConnectionsSaver(SaveFilter saveFilter, ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> localPropertieSerializer, IDataProvider<string> localPropertiesDataProvider)
|
||||
{
|
||||
_saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
|
||||
_localPropertiesSerializer = localPropertieSerializer.ThrowIfNull(nameof(localPropertieSerializer));
|
||||
_dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
|
||||
}
|
||||
private readonly SaveFilter _saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
|
||||
private readonly ISerializer<IEnumerable<LocalConnectionPropertiesModel>, string> _localPropertiesSerializer = localPropertieSerializer.ThrowIfNull(nameof(localPropertieSerializer));
|
||||
private readonly IDataProvider<string> _dataProvider = localPropertiesDataProvider.ThrowIfNull(nameof(localPropertiesDataProvider));
|
||||
|
||||
public void Save(ConnectionTreeModel connectionTreeModel, string propertyNameTrigger = "")
|
||||
{
|
||||
@@ -133,11 +127,20 @@ namespace mRemoteNG.Config.Connections
|
||||
|
||||
if (rootTreeNode != null)
|
||||
{
|
||||
dbQuery =
|
||||
databaseConnector.DbCommand(
|
||||
"INSERT INTO tblRoot (Name, Export, Protected, ConfVersion) VALUES('" +
|
||||
MiscTools.PrepareValueForDB(rootTreeNode.Name) + "', 0, '" + strProtected + "','" +
|
||||
ConnectionsFileInfo.ConnectionFileVersion + "')");
|
||||
dbQuery = databaseConnector.DbCommand(
|
||||
"INSERT INTO tblRoot (Name, Export, Protected, ConfVersion) VALUES(@Name, 0, @Protected, @Version)");
|
||||
DbParameter nameParam = dbQuery.CreateParameter();
|
||||
nameParam.ParameterName = "@Name";
|
||||
nameParam.Value = rootTreeNode.Name;
|
||||
DbParameter protectedParam = dbQuery.CreateParameter();
|
||||
protectedParam.ParameterName = "@Protected";
|
||||
protectedParam.Value = strProtected;
|
||||
DbParameter versionParam = dbQuery.CreateParameter();
|
||||
versionParam.ParameterName = "@Version";
|
||||
versionParam.Value = ConnectionsFileInfo.ConnectionFileVersion;
|
||||
dbQuery.Parameters.Add(nameParam);
|
||||
dbQuery.Parameters.Add(protectedParam);
|
||||
dbQuery.Parameters.Add(versionParam);
|
||||
dbQuery.ExecuteNonQuery();
|
||||
}
|
||||
else
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Runtime.Versioning;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Resources.Language;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
@@ -17,8 +18,13 @@ namespace mRemoteNG.Config.DataProviders
|
||||
if (WeDontNeedToBackup(fileName))
|
||||
return;
|
||||
|
||||
PathValidator.ValidatePathOrThrow(fileName, nameof(fileName));
|
||||
|
||||
string backupFileName =
|
||||
string.Format(Properties.OptionsBackupPage.Default.BackupFileNameFormat, fileName, DateTime.Now);
|
||||
|
||||
PathValidator.ValidatePathOrThrow(backupFileName, nameof(backupFileName));
|
||||
|
||||
File.Copy(fileName, backupFileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
@@ -7,6 +8,8 @@ namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
public void PruneBackupFiles(string filePath, int maxBackupsToKeep)
|
||||
{
|
||||
PathValidator.ValidatePathOrThrow(filePath, nameof(filePath));
|
||||
|
||||
string fileName = Path.GetFileName(filePath);
|
||||
string directoryName = Path.GetDirectoryName(filePath);
|
||||
|
||||
|
||||
@@ -2,18 +2,30 @@
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Tools;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class FileDataProvider : IDataProvider<string>
|
||||
{
|
||||
private string _filePath;
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public string FilePath { get; set; }
|
||||
public string FilePath
|
||||
{
|
||||
get => _filePath;
|
||||
set
|
||||
{
|
||||
PathValidator.ValidatePathOrThrow(value, nameof(FilePath));
|
||||
_filePath = value;
|
||||
}
|
||||
}
|
||||
|
||||
public FileDataProvider(string filePath)
|
||||
{
|
||||
FilePath = filePath;
|
||||
PathValidator.ValidatePathOrThrow(filePath, nameof(filePath));
|
||||
_filePath = filePath;
|
||||
}
|
||||
|
||||
public virtual string Load()
|
||||
@@ -59,6 +71,7 @@ namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
try
|
||||
{
|
||||
PathValidator.ValidatePathOrThrow(newPath, nameof(newPath));
|
||||
File.Move(FilePath, newPath);
|
||||
FilePath = newPath;
|
||||
}
|
||||
|
||||
@@ -3,14 +3,9 @@
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class FileDataProviderWithRollingBackup : FileDataProvider
|
||||
public class FileDataProviderWithRollingBackup(string filePath) : FileDataProvider(filePath)
|
||||
{
|
||||
private readonly FileBackupCreator _fileBackupCreator;
|
||||
|
||||
public FileDataProviderWithRollingBackup(string filePath) : base(filePath)
|
||||
{
|
||||
_fileBackupCreator = new FileBackupCreator();
|
||||
}
|
||||
private readonly FileBackupCreator _fileBackupCreator = new FileBackupCreator();
|
||||
|
||||
public override void Save(string content)
|
||||
{
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
public class InMemoryStringDataProvider : IDataProvider<string>
|
||||
public class InMemoryStringDataProvider(string initialContents = "") : IDataProvider<string>
|
||||
{
|
||||
private string _contents;
|
||||
|
||||
public InMemoryStringDataProvider(string initialContents = "")
|
||||
{
|
||||
_contents = initialContents;
|
||||
}
|
||||
private string _contents = initialContents;
|
||||
|
||||
public string Load()
|
||||
{
|
||||
|
||||
@@ -3,20 +3,15 @@ using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.App;
|
||||
using MySql.Data.MySqlClient;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.Config.DataProviders
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlDataProvider : IDataProvider<DataTable>
|
||||
public class SqlDataProvider(IDatabaseConnector databaseConnector) : IDataProvider<DataTable>
|
||||
{
|
||||
public IDatabaseConnector DatabaseConnector { get; }
|
||||
|
||||
public SqlDataProvider(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
DatabaseConnector = databaseConnector;
|
||||
}
|
||||
public IDatabaseConnector DatabaseConnector { get; } = databaseConnector;
|
||||
|
||||
public DataTable Load()
|
||||
{
|
||||
|
||||
@@ -1,44 +1,148 @@
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.InteropServices;
|
||||
using LiteDB;
|
||||
|
||||
namespace mRemoteNG.Config.DatabaseConnectors
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
//[SupportedOSPlatform("windows")]
|
||||
/// <summary>
|
||||
/// A helper class for testing database connectivity
|
||||
/// </summary>
|
||||
///
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
|
||||
public class DatabaseConnectionTester
|
||||
{
|
||||
public async Task<ConnectionTestResult> TestConnectivity(string type,
|
||||
string server,
|
||||
string database,
|
||||
string username,
|
||||
string password)
|
||||
public async Task<ConnectionTestResult> TestConnectivity(string type, string server, string database, string username, string password)
|
||||
{
|
||||
using (IDatabaseConnector dbConnector = DatabaseConnectorFactory.DatabaseConnector(type, server, database, username, password))
|
||||
try
|
||||
{
|
||||
try
|
||||
// Build the connection string based on the provided parameters
|
||||
string connectionString = $"Data Source={server};Initial Catalog={database};User ID={username};Password={password}";
|
||||
|
||||
// Attempt to open a connection to the database
|
||||
using (SqlConnection connection = new SqlConnection(connectionString))
|
||||
{
|
||||
await dbConnector.ConnectAsync();
|
||||
return ConnectionTestResult.ConnectionSucceded;
|
||||
await connection.OpenAsync();
|
||||
}
|
||||
catch (SqlException sqlException)
|
||||
|
||||
return ConnectionTestResult.ConnectionSucceded;
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
// Handle specific SQL exceptions
|
||||
switch (ex.Number)
|
||||
{
|
||||
if (sqlException.Message.Contains("The server was not found"))
|
||||
return ConnectionTestResult.ServerNotAccessible;
|
||||
if (sqlException.Message.Contains("Cannot open database"))
|
||||
case 4060: // Invalid Database
|
||||
return ConnectionTestResult.UnknownDatabase;
|
||||
if (sqlException.Message.Contains("Login failed for user"))
|
||||
case 18456: // Login Failed
|
||||
return ConnectionTestResult.CredentialsRejected;
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return ConnectionTestResult.UnknownError;
|
||||
case -1: // Server not accessible
|
||||
return ConnectionTestResult.ServerNotAccessible;
|
||||
default:
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Handle any other exceptions
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
}
|
||||
}
|
||||
//public class DatabaseConnectionTester
|
||||
//{
|
||||
//public async Task<ConnectionTestResult> TestConnectivity(string type, string server, string database, string username, string password)
|
||||
//{
|
||||
//using IDatabaseConnector dbConnector = DatabaseConnectorFactory.DatabaseConnector(type, server, database, username, password);
|
||||
//try
|
||||
//{
|
||||
// Validate architecture compatibility
|
||||
//if (!Environment.Is64BitProcess)
|
||||
//{
|
||||
// throw new PlatformNotSupportedException("The application must run in a 64-bit process to use this database connector.");
|
||||
// }
|
||||
|
||||
// Attempt to connect
|
||||
|
||||
//using (SqlConnection connection = new SqlConnection("Data Source=172.22.155.100,1433;Initial Catalog=Demo;Integrated Security=False;User ID=sa;Password=London123;Multiple Active Result Sets=True;Connect Timeout=30;Encrypt=True;Trust Server Certificate=True;Application Name=mRemoteNG;Application Intent=ReadOnly"))
|
||||
//{
|
||||
// connection.Open();
|
||||
// Console.WriteLine("Connection successful!");
|
||||
//}
|
||||
//Console.WriteLine($"{RuntimeInformation.OSArchitecture}");
|
||||
//Console.WriteLine($"{RuntimeInformation.ProcessArchitecture}");
|
||||
//try
|
||||
//{
|
||||
// using (SqlConnection connection = new SqlConnection("Data Source=172.22.155.100,1433;Initial Catalog=Demo;Integrated Security=False;User ID=sa;Password=London123;Multiple Active Result Sets=True;Connect Timeout=30;Encrypt=True;Trust Server Certificate=True;Application Name=mRemoteNG;Application Intent=ReadOnly"))
|
||||
// {
|
||||
// connection.Open();
|
||||
// Console.WriteLine("Connection successful!");
|
||||
// }
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Console.WriteLine($"Connection failed: {ex.Message}");
|
||||
//}
|
||||
//}
|
||||
/*
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (SqlConnection connection = new SqlConnection("Data Source=172.22.155.100,1433;Initial Catalog=Demo;Integrated Security=False;User ID=sa;Password=London123;Multiple Active Result Sets=True;Connect Timeout=30;Encrypt=True;Trust Server Certificate=True;Application Name=mRemoteNG;Application Intent=ReadOnly"))
|
||||
{
|
||||
connection.Open();
|
||||
}
|
||||
}
|
||||
catch (TypeInitializationException ex)
|
||||
{
|
||||
Console.WriteLine($"Type initialization error: {ex.InnerException?.Message}");
|
||||
}
|
||||
|
||||
|
||||
//await dbConnector.ConnectAsync();
|
||||
return ConnectionTestResult.ConnectionSucceded;
|
||||
}
|
||||
catch (PlatformNotSupportedException ex)
|
||||
{
|
||||
// Log or handle architecture mismatch
|
||||
Console.WriteLine($"Platform error: {ex.Message}");
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
catch (DllNotFoundException ex)
|
||||
{
|
||||
// Handle missing native dependencies
|
||||
Console.WriteLine($"Missing dependency: {ex.Message}");
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
catch (BadImageFormatException ex)
|
||||
{
|
||||
// Handle architecture mismatch in native libraries
|
||||
Console.WriteLine($"Architecture mismatch: {ex.Message}");
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
catch (SqlException sqlException)
|
||||
{
|
||||
if (sqlException.Message.Contains("The server was not found"))
|
||||
return ConnectionTestResult.ServerNotAccessible;
|
||||
if (sqlException.Message.Contains("Cannot open database"))
|
||||
return ConnectionTestResult.UnknownDatabase;
|
||||
if (sqlException.Message.Contains("Login failed for user"))
|
||||
return ConnectionTestResult.CredentialsRejected;
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log unexpected errors
|
||||
Console.WriteLine($"Unexpected error: {ex.Message}");
|
||||
return ConnectionTestResult.UnknownError;
|
||||
}
|
||||
*/
|
||||
// }
|
||||
// }
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
using System.Data;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Threading.Tasks;
|
||||
using static BrightIdeasSoftware.TreeListView;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
@@ -9,7 +10,7 @@ namespace mRemoteNG.Config.DatabaseConnectors
|
||||
{
|
||||
public class MSSqlDatabaseConnector : IDatabaseConnector
|
||||
{
|
||||
private DbConnection _dbConnection { get; set; } = default(SqlConnection);
|
||||
private DbConnection _dbConnection { get; set; } = default!;
|
||||
private string _dbConnectionString = "";
|
||||
private readonly string _dbHost;
|
||||
private readonly string _dbCatalog;
|
||||
@@ -58,10 +59,17 @@ namespace mRemoteNG.Config.DatabaseConnectors
|
||||
|
||||
_dbConnectionString = new SqlConnectionStringBuilder
|
||||
{
|
||||
ApplicationName = "mRemoteNG",
|
||||
ApplicationIntent = ApplicationIntent.ReadOnly,
|
||||
DataSource = $"{hostParts[0]},{_dbPort}",
|
||||
InitialCatalog = _dbCatalog,
|
||||
UserID = _dbUsername,
|
||||
Password = _dbPassword,
|
||||
IntegratedSecurity = false,
|
||||
Encrypt = true,
|
||||
TrustServerCertificate = true,
|
||||
ConnectTimeout = 30,
|
||||
MultipleActiveResultSets = true
|
||||
}.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,9 @@ using mRemoteNG.Tools;
|
||||
namespace mRemoteNG.Config.Import
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class PortScanImporter : IConnectionImporter<IEnumerable<ScanHost>>
|
||||
public class PortScanImporter(ProtocolType targetProtocolType) : IConnectionImporter<IEnumerable<ScanHost>>
|
||||
{
|
||||
private readonly ProtocolType _targetProtocolType;
|
||||
|
||||
public PortScanImporter(ProtocolType targetProtocolType)
|
||||
{
|
||||
_targetProtocolType = targetProtocolType;
|
||||
}
|
||||
private readonly ProtocolType _targetProtocolType = targetProtocolType;
|
||||
|
||||
public void Import(IEnumerable<ScanHost> hosts, ContainerInfo destinationContainer)
|
||||
{
|
||||
|
||||
140
mRemoteNG/Config/MachineIdentifier.cs
Normal file
140
mRemoteNG/Config/MachineIdentifier.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Management;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace mRemoteNG.Config.MachineIdentifier
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
/// <summary>
|
||||
/// Provides functionality to generate a consistent and unique machine identifier
|
||||
/// based on hardware properties (disk serial number, MAC address, BIOS UUID, and machine name).
|
||||
/// This class is supported only on Windows.
|
||||
/// </summary>
|
||||
public static class MachineIdentifierGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a consistent machine identifier by combining hardware-based identifiers
|
||||
/// (disk serial number, MAC address, BIOS UUID, and machine name) and hashing the result.
|
||||
/// </summary>
|
||||
/// <returns>A consistent and unique identifier for the machine.</returns>
|
||||
/// <exception cref="PlatformNotSupportedException">Thrown if the method is called on a non-Windows platform.</exception>
|
||||
public static string GenerateMachineIdentifier()
|
||||
{
|
||||
// Ensure the code runs only on Windows
|
||||
if (!OperatingSystem.IsWindows())
|
||||
{
|
||||
throw new PlatformNotSupportedException("This method is supported only on Windows.");
|
||||
}
|
||||
|
||||
// Retrieve hardware-based identifiers (with fallbacks)
|
||||
string diskId = GetDiskSerialNumber() ?? "NO_DISK_ID";
|
||||
string macAddress = GetMacAddress() ?? "NO_MAC_ADDRESS";
|
||||
string biosUuid = GetBiosUuid() ?? "NO_BIOS_UUID";
|
||||
string machineName = Environment.MachineName;
|
||||
|
||||
// Combine them into a single string
|
||||
string combined = $"{diskId}_{macAddress}_{biosUuid}_{machineName}";
|
||||
|
||||
// Hash the combined string to ensure a fixed length and improve security
|
||||
using (SHA256 sha256 = SHA256.Create())
|
||||
{
|
||||
byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(combined));
|
||||
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the serial number of the first physical disk using WMI.
|
||||
/// </summary>
|
||||
/// <returns>The disk serial number, or null if the serial number cannot be retrieved.</returns>
|
||||
private static string GetDiskSerialNumber()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (ManagementObjectSearcher searcher = new("SELECT SerialNumber FROM Win32_DiskDrive"))
|
||||
{
|
||||
foreach (ManagementObject wmi_HD in searcher.Get())
|
||||
{
|
||||
if (wmi_HD["SerialNumber"] != null)
|
||||
{
|
||||
string serialNumber = wmi_HD["SerialNumber"].ToString().Trim();
|
||||
if (!string.IsNullOrEmpty(serialNumber))
|
||||
{
|
||||
return serialNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error retrieving disk serial number: {ex.Message}");
|
||||
}
|
||||
|
||||
return null; // Return null if the disk serial number cannot be retrieved
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the MAC address of the first active network adapter.
|
||||
/// </summary>
|
||||
/// <returns>The MAC address, or null if the MAC address cannot be retrieved.</returns>
|
||||
private static string GetMacAddress()
|
||||
{
|
||||
try
|
||||
{
|
||||
NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface adapter in interfaces)
|
||||
{
|
||||
if (adapter.OperationalStatus == OperationalStatus.Up)
|
||||
{
|
||||
string macAddress = adapter.GetPhysicalAddress().ToString();
|
||||
if (!string.IsNullOrEmpty(macAddress))
|
||||
{
|
||||
return macAddress;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error retrieving MAC address: {ex.Message}");
|
||||
}
|
||||
|
||||
return null; // Return null if the MAC address cannot be retrieved
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the BIOS UUID of the machine using WMI.
|
||||
/// </summary>
|
||||
/// <returns>The BIOS UUID, or null if the UUID cannot be retrieved.</returns>
|
||||
private static string GetBiosUuid()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct"))
|
||||
{
|
||||
foreach (ManagementObject wmi_HD in searcher.Get())
|
||||
{
|
||||
if (wmi_HD["UUID"] != null)
|
||||
{
|
||||
string uuid = wmi_HD["UUID"].ToString().Trim();
|
||||
if (!string.IsNullOrEmpty(uuid))
|
||||
{
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error retrieving BIOS UUID: {ex.Message}");
|
||||
}
|
||||
|
||||
return null; // Return null if the BIOS UUID cannot be retrieved
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,8 @@ using mRemoteNG.Connection;
|
||||
|
||||
namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
public class PuttySessionChangedEventArgs : EventArgs
|
||||
public class PuttySessionChangedEventArgs(PuttySessionInfo sessionChanged = null) : EventArgs
|
||||
{
|
||||
public PuttySessionInfo Session { get; set; }
|
||||
|
||||
public PuttySessionChangedEventArgs(PuttySessionInfo sessionChanged = null)
|
||||
{
|
||||
Session = sessionChanged;
|
||||
}
|
||||
public PuttySessionInfo Session { get; set; } = sessionChanged;
|
||||
}
|
||||
}
|
||||
@@ -135,17 +135,17 @@ namespace mRemoteNG.Config.Putty
|
||||
{
|
||||
public static string[] Names => Instance.GetSessionNames();
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
|
||||
{
|
||||
return new StandardValuesCollection(Names);
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -113,8 +113,10 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
: "";
|
||||
|
||||
connectionRecord.Password = headers.Contains("Password")
|
||||
? connectionCsv[headers.IndexOf("Password")].ConvertToSecureString()
|
||||
: "".ConvertToSecureString();
|
||||
// ? connectionCsv[headers.IndexOf("Password")].ConvertToSecureString()
|
||||
// : "".ConvertToSecureString();
|
||||
? connectionCsv[headers.IndexOf("Password")]
|
||||
: "";
|
||||
|
||||
connectionRecord.Domain = headers.Contains("Domain")
|
||||
? connectionCsv[headers.IndexOf("Domain")]
|
||||
|
||||
@@ -112,7 +112,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv
|
||||
sb.Append(FormatForCsv(con.Username));
|
||||
|
||||
if (_saveFilter.SavePassword)
|
||||
sb.Append(con.Password?.ConvertToUnsecureString() + ";");
|
||||
//sb.Append(con.Password?.ConvertToUnsecureString() + ";");
|
||||
sb.Append(con.Password + ";");
|
||||
|
||||
if (_saveFilter.SaveDomain)
|
||||
sb.Append(FormatForCsv(con.Domain));
|
||||
|
||||
@@ -131,7 +131,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Csv.RemoteDesktopMa
|
||||
Hostname = hostString,
|
||||
Port = port,
|
||||
Username = username,
|
||||
Password = password?.ConvertToSecureString(),
|
||||
//Password = password?.ConvertToSecureString(),
|
||||
Password = password,
|
||||
Domain = domain,
|
||||
Icon = connectionType.IconName ?? "mRemoteNG",
|
||||
Description = description,
|
||||
|
||||
@@ -21,16 +21,10 @@ using mRemoteNG.Tree.Root;
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Sql
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class DataTableDeserializer : IDeserializer<DataTable, ConnectionTreeModel>
|
||||
public class DataTableDeserializer(ICryptographyProvider cryptographyProvider, SecureString decryptionKey) : IDeserializer<DataTable, ConnectionTreeModel>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _decryptionKey;
|
||||
|
||||
public DataTableDeserializer(ICryptographyProvider cryptographyProvider, SecureString decryptionKey)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
|
||||
}
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
private readonly SecureString _decryptionKey = decryptionKey.ThrowIfNull(nameof(decryptionKey));
|
||||
|
||||
public ConnectionTreeModel Deserialize(DataTable table)
|
||||
{
|
||||
@@ -113,7 +107,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Sql
|
||||
connectionInfo.OpeningCommand = (string)dataRow["OpeningCommand"];
|
||||
connectionInfo.Panel = (string)dataRow["Panel"];
|
||||
var pw = dataRow["Password"] as string;
|
||||
connectionInfo.Password = DecryptValue(pw ?? "").ConvertToSecureString();
|
||||
//connectionInfo.Password = DecryptValue(pw ?? "").ConvertToSecureString();
|
||||
connectionInfo.Password = DecryptValue(pw ?? "");
|
||||
connectionInfo.Port = (int)dataRow["Port"];
|
||||
connectionInfo.PostExtApp = (string)dataRow["PostExtApp"];
|
||||
connectionInfo.PreExtApp = (string)dataRow["PreExtApp"];
|
||||
|
||||
@@ -14,27 +14,20 @@ using mRemoteNG.Tree.Root;
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Sql
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class DataTableSerializer : ISerializer<ConnectionInfo, DataTable>
|
||||
public class DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey) : ISerializer<ConnectionInfo, DataTable>
|
||||
{
|
||||
private const int DELETE = 0;
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _encryptionKey;
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
private readonly SecureString _encryptionKey = encryptionKey.ThrowIfNull(nameof(encryptionKey));
|
||||
private DataTable _dataTable;
|
||||
private DataTable _sourceDataTable;
|
||||
private readonly Dictionary<string, int> _sourcePrimaryKeyDict = [];
|
||||
private const string TABLE_NAME = "tblCons";
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private readonly SaveFilter _saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
|
||||
private int _currentNodeIndex;
|
||||
|
||||
public Version Version { get; } = new Version(3, 0);
|
||||
|
||||
public DataTableSerializer(SaveFilter saveFilter, ICryptographyProvider cryptographyProvider, SecureString encryptionKey)
|
||||
{
|
||||
_saveFilter = saveFilter.ThrowIfNull(nameof(saveFilter));
|
||||
_cryptographyProvider = cryptographyProvider.ThrowIfNull(nameof(cryptographyProvider));
|
||||
_encryptionKey = encryptionKey.ThrowIfNull(nameof(encryptionKey));
|
||||
}
|
||||
|
||||
public void SetSourceDataTable(DataTable sourceDataTable)
|
||||
{
|
||||
_sourceDataTable = sourceDataTable;
|
||||
@@ -519,7 +512,10 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Sql
|
||||
dataRow["InheritVNCViewOnly"].Equals(false);
|
||||
}
|
||||
|
||||
bool pwd = dataRow["Password"].Equals(_saveFilter.SavePassword ? _cryptographyProvider.Encrypt(connectionInfo.Password?.ConvertToUnsecureString(), _encryptionKey) : "") &&
|
||||
//bool pwd = dataRow["Password"].Equals(_saveFilter.SavePassword ? _cryptographyProvider.Encrypt(connectionInfo.Password?.ConvertToUnsecureString(), _encryptionKey) : "") &&
|
||||
// dataRow["VNCProxyPassword"].Equals(_cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey)) &&
|
||||
// dataRow["RDGatewayPassword"].Equals(_cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey));
|
||||
bool pwd = dataRow["Password"].Equals(_saveFilter.SavePassword ? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey) : "") &&
|
||||
dataRow["VNCProxyPassword"].Equals(_cryptographyProvider.Encrypt(connectionInfo.VNCProxyPassword, _encryptionKey)) &&
|
||||
dataRow["RDGatewayPassword"].Equals(_cryptographyProvider.Encrypt(connectionInfo.RDGatewayPassword, _encryptionKey));
|
||||
return !(pwd && isFieldNotChange && isInheritanceFieldNotChange);
|
||||
@@ -572,10 +568,11 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Sql
|
||||
dataRow["MacAddress"] = connectionInfo.MacAddress;
|
||||
dataRow["Name"] = connectionInfo.Name;
|
||||
dataRow["OpeningCommand"] = connectionInfo.OpeningCommand;
|
||||
dataRow["OpeningCommand"] = connectionInfo.OpeningCommand;
|
||||
// dataRow["OpeningCommand"] = connectionInfo.OpeningCommand; dublicate?
|
||||
dataRow["Panel"] = connectionInfo.Panel;
|
||||
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword ? _cryptographyProvider.Encrypt(connectionInfo.Password?.ConvertToUnsecureString(), _encryptionKey) : "";
|
||||
//dataRow["Password"] = _saveFilter.SavePassword ? _cryptographyProvider.Encrypt(connectionInfo.Password?.ConvertToUnsecureString(), _encryptionKey) : "";
|
||||
dataRow["Password"] = _saveFilter.SavePassword ? _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey) : "";
|
||||
dataRow["Port"] = connectionInfo.Port;
|
||||
dataRow["PositionID"] = _currentNodeIndex;
|
||||
dataRow["PostExtApp"] = connectionInfo.PostExtApp;
|
||||
|
||||
@@ -61,7 +61,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
: new XAttribute("Domain", ""));
|
||||
|
||||
if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password)
|
||||
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password.ConvertToUnsecureString(), _encryptionKey)));
|
||||
//element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password.ConvertToUnsecureString(), _encryptionKey)));
|
||||
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)));
|
||||
else
|
||||
element.Add(new XAttribute("Password", ""));
|
||||
|
||||
|
||||
@@ -11,23 +11,16 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class XmlConnectionNodeSerializer27 : ISerializer<ConnectionInfo, XElement>
|
||||
public class XmlConnectionNodeSerializer27(ICryptographyProvider cryptographyProvider,
|
||||
SecureString encryptionKey,
|
||||
SaveFilter saveFilter) : ISerializer<ConnectionInfo, XElement>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _encryptionKey;
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider ?? throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
private readonly SecureString _encryptionKey = encryptionKey ?? throw new ArgumentNullException(nameof(encryptionKey));
|
||||
private readonly SaveFilter _saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
|
||||
|
||||
public Version Version { get; } = new Version(2, 7);
|
||||
|
||||
public XmlConnectionNodeSerializer27(ICryptographyProvider cryptographyProvider,
|
||||
SecureString encryptionKey,
|
||||
SaveFilter saveFilter)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider ?? throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
_encryptionKey = encryptionKey ?? throw new ArgumentNullException(nameof(encryptionKey));
|
||||
_saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
|
||||
}
|
||||
|
||||
public XElement Serialize(ConnectionInfo connectionInfo)
|
||||
{
|
||||
XElement element = new(XName.Get("Node", ""));
|
||||
@@ -62,7 +55,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
: new XAttribute("Domain", ""));
|
||||
|
||||
if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password)
|
||||
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password.ConvertToUnsecureString(), _encryptionKey)));
|
||||
//element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password.ConvertToUnsecureString(), _encryptionKey)));
|
||||
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)));
|
||||
else
|
||||
element.Add(new XAttribute("Password", ""));
|
||||
}
|
||||
|
||||
@@ -11,23 +11,16 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class XmlConnectionNodeSerializer28 : ISerializer<ConnectionInfo, XElement>
|
||||
public class XmlConnectionNodeSerializer28(ICryptographyProvider cryptographyProvider,
|
||||
SecureString encryptionKey,
|
||||
SaveFilter saveFilter) : ISerializer<ConnectionInfo, XElement>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly SecureString _encryptionKey;
|
||||
private readonly SaveFilter _saveFilter;
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider ?? throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
private readonly SecureString _encryptionKey = encryptionKey ?? throw new ArgumentNullException(nameof(encryptionKey));
|
||||
private readonly SaveFilter _saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
|
||||
|
||||
public Version Version { get; } = new Version(2, 8);
|
||||
|
||||
public XmlConnectionNodeSerializer28(ICryptographyProvider cryptographyProvider,
|
||||
SecureString encryptionKey,
|
||||
SaveFilter saveFilter)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider ?? throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
_encryptionKey = encryptionKey ?? throw new ArgumentNullException(nameof(encryptionKey));
|
||||
_saveFilter = saveFilter ?? throw new ArgumentNullException(nameof(saveFilter));
|
||||
}
|
||||
|
||||
public XElement Serialize(ConnectionInfo connectionInfo)
|
||||
{
|
||||
XElement element = new(XName.Get("Node", ""));
|
||||
@@ -49,6 +42,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
element.Add(new XAttribute("Descr", connectionInfo.Description));
|
||||
element.Add(new XAttribute("Icon", connectionInfo.Icon));
|
||||
element.Add(new XAttribute("Panel", connectionInfo.Panel));
|
||||
element.Add(new XAttribute("TabColor", connectionInfo.TabColor));
|
||||
element.Add(new XAttribute("Id", connectionInfo.ConstantID));
|
||||
|
||||
if (!Runtime.UseCredentialManager)
|
||||
@@ -62,7 +56,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
: new XAttribute("Domain", ""));
|
||||
|
||||
if (_saveFilter.SavePassword && !connectionInfo.Inheritance.Password)
|
||||
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password?.ConvertToUnsecureString(), _encryptionKey)));
|
||||
//element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password?.ConvertToUnsecureString(), _encryptionKey)));
|
||||
element.Add(new XAttribute("Password", _cryptographyProvider.Encrypt(connectionInfo.Password, _encryptionKey)));
|
||||
else
|
||||
element.Add(new XAttribute("Password", ""));
|
||||
}
|
||||
@@ -193,6 +188,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
element.Add(new XAttribute("InheritIcon", inheritance.Icon.ToString().ToLowerInvariant()));
|
||||
if (inheritance.Panel)
|
||||
element.Add(new XAttribute("InheritPanel", inheritance.Panel.ToString().ToLowerInvariant()));
|
||||
if (inheritance.TabColor)
|
||||
element.Add(new XAttribute("InheritTabColor", inheritance.TabColor.ToString().ToLowerInvariant()));
|
||||
if (inheritance.Password)
|
||||
element.Add(new XAttribute("InheritPassword", inheritance.Password.ToString().ToLowerInvariant()));
|
||||
if (inheritance.Port)
|
||||
|
||||
@@ -94,8 +94,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
connections = _decryptor.LegacyFullFileDecrypt(connections);
|
||||
if (connections != "")
|
||||
{
|
||||
_xmlDocument = new XmlDocument();
|
||||
_xmlDocument.LoadXml(connections);
|
||||
_xmlDocument = SecureXmlHelper.LoadXmlFromString(connections);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,8 +216,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
if (!Runtime.UseCredentialManager || _confVersion <= 2.6) // 0.2 - 2.6
|
||||
{
|
||||
connectionInfo.Username = xmlnode.GetAttributeAsString("Username");
|
||||
//connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
|
||||
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password")).ConvertToSecureString();
|
||||
connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password"));
|
||||
//connectionInfo.Password = _decryptor.Decrypt(xmlnode.GetAttributeAsString("Password")).ConvertToSecureString();
|
||||
connectionInfo.Domain = xmlnode.GetAttributeAsString("Domain");
|
||||
}
|
||||
}
|
||||
@@ -329,6 +328,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
connectionInfo.Inheritance.DisplayWallpaper = xmlnode.GetAttributeAsBool("InheritDisplayWallpaper");
|
||||
connectionInfo.Inheritance.Icon = xmlnode.GetAttributeAsBool("InheritIcon");
|
||||
connectionInfo.Inheritance.Panel = xmlnode.GetAttributeAsBool("InheritPanel");
|
||||
connectionInfo.Inheritance.TabColor = xmlnode.GetAttributeAsBool("InheritTabColor");
|
||||
connectionInfo.Inheritance.Port = xmlnode.GetAttributeAsBool("InheritPort");
|
||||
connectionInfo.Inheritance.Protocol = xmlnode.GetAttributeAsBool("InheritProtocol");
|
||||
connectionInfo.Inheritance.PuttySession = xmlnode.GetAttributeAsBool("InheritPuttySession");
|
||||
@@ -351,6 +351,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
|
||||
connectionInfo.Icon = xmlnode.GetAttributeAsString("Icon");
|
||||
connectionInfo.Panel = xmlnode.GetAttributeAsString("Panel");
|
||||
connectionInfo.TabColor = xmlnode.GetAttributeAsString("TabColor");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -12,17 +12,11 @@ using mRemoteNG.Tree.Root;
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class XmlConnectionsDocumentCompiler
|
||||
public class XmlConnectionsDocumentCompiler(ICryptographyProvider cryptographyProvider, ISerializer<ConnectionInfo, XElement> connectionNodeSerializer)
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider ?? throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
private SecureString _encryptionKey;
|
||||
private readonly ISerializer<ConnectionInfo, XElement> _connectionNodeSerializer;
|
||||
|
||||
public XmlConnectionsDocumentCompiler(ICryptographyProvider cryptographyProvider, ISerializer<ConnectionInfo, XElement> connectionNodeSerializer)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider ?? throw new ArgumentNullException(nameof(cryptographyProvider));
|
||||
_connectionNodeSerializer = connectionNodeSerializer ?? throw new ArgumentNullException(nameof(connectionNodeSerializer));
|
||||
}
|
||||
private readonly ISerializer<ConnectionInfo, XElement> _connectionNodeSerializer = connectionNodeSerializer ?? throw new ArgumentNullException(nameof(connectionNodeSerializer));
|
||||
|
||||
public XDocument CompileDocument(ConnectionTreeModel connectionTreeModel, bool fullFileEncryption)
|
||||
{
|
||||
|
||||
@@ -4,14 +4,9 @@ using mRemoteNG.Security;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
public class XmlConnectionsDocumentEncryptor
|
||||
public class XmlConnectionsDocumentEncryptor(ICryptographyProvider cryptographyProvider)
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
|
||||
public XmlConnectionsDocumentEncryptor(ICryptographyProvider cryptographyProvider)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
}
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider;
|
||||
|
||||
public XDocument EncryptDocument(XDocument documentToEncrypt, SecureString encryptionKey)
|
||||
{
|
||||
|
||||
@@ -14,22 +14,16 @@ using mRemoteNG.Tree.Root;
|
||||
namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class XmlConnectionsSerializer : ISerializer<ConnectionTreeModel, string>,
|
||||
public class XmlConnectionsSerializer(ICryptographyProvider cryptographyProvider,
|
||||
ISerializer<ConnectionInfo, XElement> connectionNodeSerializer) : ISerializer<ConnectionTreeModel, string>,
|
||||
ISerializer<ConnectionInfo, string>
|
||||
{
|
||||
private readonly ICryptographyProvider _cryptographyProvider;
|
||||
private readonly ISerializer<ConnectionInfo, XElement> _connectionNodeSerializer;
|
||||
private readonly ICryptographyProvider _cryptographyProvider = cryptographyProvider;
|
||||
private readonly ISerializer<ConnectionInfo, XElement> _connectionNodeSerializer = connectionNodeSerializer;
|
||||
|
||||
public Version Version => _connectionNodeSerializer.Version;
|
||||
public bool UseFullEncryption { get; set; }
|
||||
|
||||
public XmlConnectionsSerializer(ICryptographyProvider cryptographyProvider,
|
||||
ISerializer<ConnectionInfo, XElement> connectionNodeSerializer)
|
||||
{
|
||||
_cryptographyProvider = cryptographyProvider;
|
||||
_connectionNodeSerializer = connectionNodeSerializer;
|
||||
}
|
||||
|
||||
public string Serialize(ConnectionTreeModel connectionTreeModel)
|
||||
{
|
||||
RootNodeInfo rootNode = (RootNodeInfo)connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
|
||||
|
||||
@@ -15,16 +15,10 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ActiveDirectoryDeserializer
|
||||
public class ActiveDirectoryDeserializer(string ldapPath, bool importSubOu)
|
||||
{
|
||||
private readonly string _ldapPath;
|
||||
private readonly bool _importSubOu;
|
||||
|
||||
public ActiveDirectoryDeserializer(string ldapPath, bool importSubOu)
|
||||
{
|
||||
_ldapPath = ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath));
|
||||
_importSubOu = importSubOu;
|
||||
}
|
||||
private readonly string _ldapPath = ldapPath.ThrowIfNullOrEmpty(nameof(ldapPath));
|
||||
private readonly bool _importSubOu = importSubOu;
|
||||
|
||||
public ConnectionTreeModel Deserialize()
|
||||
{
|
||||
|
||||
@@ -10,14 +10,9 @@ using mRemoteNG.Tree.Root;
|
||||
namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class PortScanDeserializer : IDeserializer<IEnumerable<ScanHost>, ConnectionTreeModel>
|
||||
public class PortScanDeserializer(ProtocolType targetProtocolType) : IDeserializer<IEnumerable<ScanHost>, ConnectionTreeModel>
|
||||
{
|
||||
private readonly ProtocolType _targetProtocolType;
|
||||
|
||||
public PortScanDeserializer(ProtocolType targetProtocolType)
|
||||
{
|
||||
_targetProtocolType = targetProtocolType;
|
||||
}
|
||||
private readonly ProtocolType _targetProtocolType = targetProtocolType;
|
||||
|
||||
public ConnectionTreeModel Deserialize(IEnumerable<ScanHost> scannedHosts)
|
||||
{
|
||||
@@ -66,6 +61,10 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
if (host.Vnc)
|
||||
finalProtocol = ProtocolType.VNC;
|
||||
break;
|
||||
case ProtocolType.ARD:
|
||||
if (host.Vnc)
|
||||
finalProtocol = ProtocolType.ARD;
|
||||
break;
|
||||
default:
|
||||
protocolValid = false;
|
||||
break;
|
||||
|
||||
@@ -20,8 +20,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
RootNodeInfo root = new(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
|
||||
XmlDocument xmlDocument = new();
|
||||
xmlDocument.LoadXml(puttycmConnectionsXml);
|
||||
XmlDocument xmlDocument = SecureXmlHelper.LoadXmlFromString(puttycmConnectionsXml);
|
||||
|
||||
XmlNode configurationNode = xmlDocument.SelectSingleNode("/configuration");
|
||||
|
||||
@@ -134,7 +133,8 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
|
||||
XmlNode loginNode = xmlNode.SelectSingleNode("./login");
|
||||
connectionInfo.Username = loginNode?.SelectSingleNode("login")?.InnerText;
|
||||
connectionInfo.Password = loginNode?.SelectSingleNode("password")?.InnerText.ConvertToSecureString();
|
||||
//connectionInfo.Password = loginNode?.SelectSingleNode("password")?.InnerText.ConvertToSecureString();
|
||||
connectionInfo.Password = loginNode?.SelectSingleNode("password")?.InnerText;
|
||||
// ./prompt
|
||||
|
||||
// ./timeout/connectiontimeout
|
||||
|
||||
@@ -101,6 +101,9 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
case "allow desktop composition":
|
||||
connectionInfo.EnableDesktopComposition = value == "1";
|
||||
break;
|
||||
case "keyboardhook":
|
||||
connectionInfo.RedirectKeys = value == "1";
|
||||
break;
|
||||
case "redirectsmartcards":
|
||||
connectionInfo.RedirectSmartCards = value == "1";
|
||||
break;
|
||||
@@ -156,6 +159,34 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
case "gatewayhostname":
|
||||
connectionInfo.RDGatewayHostname = value;
|
||||
break;
|
||||
case "gatewaycredentialssource":
|
||||
switch(value)
|
||||
{
|
||||
case "0":
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.ExternalCredentialProvider;
|
||||
break;
|
||||
case "1":
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.SmartCard;
|
||||
break;
|
||||
case "2":
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.Yes;
|
||||
break;
|
||||
case "3":
|
||||
// Both 3 and 4 require that the user enter gateway credentials manually
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.No;
|
||||
break;
|
||||
case "4":
|
||||
// Both 3 and 4 require that the user enter gateway credentials manually
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.No;
|
||||
break;
|
||||
case "5":
|
||||
connectionInfo.RDGatewayUseConnectionCredentials = RDGatewayUseConnectionCredentials.AccessToken;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "gatewayaccesstoken":
|
||||
connectionInfo.RDGatewayAccessToken = value;
|
||||
break;
|
||||
case "alternate shell":
|
||||
connectionInfo.RDPStartProgram = value;
|
||||
break;
|
||||
|
||||
@@ -26,9 +26,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
ConnectionTreeModel connectionTreeModel = new();
|
||||
RootNodeInfo root = new(RootNodeType.Connection);
|
||||
|
||||
XmlDocument xmlDocument = new();
|
||||
xmlDocument.LoadXml(rdcmConnectionsXml);
|
||||
|
||||
XmlDocument xmlDocument = SecureXmlHelper.LoadXmlFromString(rdcmConnectionsXml);
|
||||
|
||||
XmlNode rdcManNode = xmlDocument.SelectSingleNode("/RDCMan");
|
||||
VerifySchemaVersion(rdcManNode);
|
||||
@@ -164,12 +162,15 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
if (_schemaVersion == 1) // Version 2.2 allows clear text passwords
|
||||
{
|
||||
connectionInfo.Password = passwordNode?.Attributes?["storeAsClearText"]?.Value == "True"
|
||||
? passwordNode.InnerText.ConvertToSecureString()
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText).ConvertToSecureString();
|
||||
//? passwordNode.InnerText.ConvertToSecureString()
|
||||
//: DecryptRdcManPassword(passwordNode?.InnerText).ConvertToSecureString();
|
||||
? passwordNode.InnerText
|
||||
: DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionInfo.Password = DecryptRdcManPassword(passwordNode?.InnerText).ConvertToSecureString();
|
||||
//connectionInfo.Password = DecryptRdcManPassword(passwordNode?.InnerText).ConvertToSecureString();
|
||||
connectionInfo.Password = DecryptRdcManPassword(passwordNode?.InnerText);
|
||||
}
|
||||
|
||||
connectionInfo.Domain = logonCredentialsNode.SelectSingleNode("./domain")?.InnerText ?? string.Empty;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using mRemoteNG.Connection;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Container;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tree;
|
||||
using mRemoteNG.Tree.Root;
|
||||
using System;
|
||||
@@ -22,8 +23,7 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
RootNodeInfo root = new(RootNodeType.Connection);
|
||||
connectionTreeModel.AddRootNode(root);
|
||||
|
||||
XmlDocument xmlDocument = new();
|
||||
xmlDocument.LoadXml(content);
|
||||
XmlDocument xmlDocument = SecureXmlHelper.LoadXmlFromString(content);
|
||||
|
||||
XmlNode sessionsNode = xmlDocument.SelectSingleNode("/VanDyke/key[@name=\"Sessions\"]");
|
||||
|
||||
|
||||
@@ -9,16 +9,11 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlDatabaseVersionVerifier
|
||||
public class SqlDatabaseVersionVerifier(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
private readonly Version _currentSupportedVersion = new(3, 0);
|
||||
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlDatabaseVersionVerifier(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool VerifyDatabaseVersion(Version dbVersion)
|
||||
{
|
||||
|
||||
@@ -7,14 +7,9 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion22To23Upgrader : IVersionUpgrader
|
||||
public class SqlVersion22To23Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion22To23Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -7,14 +7,9 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion23To24Upgrader : IVersionUpgrader
|
||||
public class SqlVersion23To24Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion23To24Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -7,14 +7,9 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion24To25Upgrader : IVersionUpgrader
|
||||
public class SqlVersion24To25Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion24To25Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -7,14 +7,9 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion25To26Upgrader : IVersionUpgrader
|
||||
public class SqlVersion25To26Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion25To26Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -2,20 +2,15 @@
|
||||
using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion26To27Upgrader : IVersionUpgrader
|
||||
public class SqlVersion26To27Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion26To27Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -3,20 +3,15 @@ using mRemoteNG.Config.DatabaseConnectors;
|
||||
using mRemoteNG.Messages;
|
||||
using System;
|
||||
using System.Data.Common;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion27To28Upgrader : IVersionUpgrader
|
||||
public class SqlVersion27To28Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion27To28Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -8,15 +8,10 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion28To29Upgrader : IVersionUpgrader
|
||||
public class SqlVersion28To29Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly Version _version = new(2, 9);
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion28To29Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -8,15 +8,10 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Config.Serializers.Versioning
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class SqlVersion29To30Upgrader : IVersionUpgrader
|
||||
public class SqlVersion29To30Upgrader(IDatabaseConnector databaseConnector) : IVersionUpgrader
|
||||
{
|
||||
private readonly Version _version = new(3, 0);
|
||||
private readonly IDatabaseConnector _databaseConnector;
|
||||
|
||||
public SqlVersion29To30Upgrader(IDatabaseConnector databaseConnector)
|
||||
{
|
||||
_databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
}
|
||||
private readonly IDatabaseConnector _databaseConnector = databaseConnector ?? throw new ArgumentNullException(nameof(databaseConnector));
|
||||
|
||||
public bool CanUpgrade(Version currentVersion)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using mRemoteNG.UI.Forms;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using mRemoteNG.Messages;
|
||||
using mRemoteNG.Security;
|
||||
using mRemoteNG.Tools;
|
||||
using mRemoteNG.UI.Controls;
|
||||
using System.Runtime.Versioning;
|
||||
@@ -40,18 +41,18 @@ namespace mRemoteNG.Config.Settings
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), GeneralAppInfo.ProductName, SettingsFileInfo.ExtAppsFilesName);
|
||||
#endif
|
||||
string newPath = Path.Combine(SettingsFileInfo.SettingsPath, SettingsFileInfo.ExtAppsFilesName);
|
||||
XmlDocument xDom = new();
|
||||
XmlDocument xDom;
|
||||
if (File.Exists(newPath))
|
||||
{
|
||||
_messageCollector.AddMessage(MessageClass.InformationMsg, $"Loading External Apps from: {newPath}",
|
||||
true);
|
||||
xDom.Load(newPath);
|
||||
xDom = SecureXmlHelper.LoadXmlFromFile(newPath);
|
||||
}
|
||||
#if !PORTABLE
|
||||
else if (File.Exists(oldPath))
|
||||
{
|
||||
_messageCollector.AddMessage(MessageClass.InformationMsg, $"Loading External Apps from: {oldPath}", true);
|
||||
xDom.Load(oldPath);
|
||||
xDom = SecureXmlHelper.LoadXmlFromFile(oldPath);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Management;
|
||||
using JsonSerializer = System.Text.Json.JsonSerializer;
|
||||
using LiteDB;
|
||||
using System.Linq;
|
||||
using LiteDB;
|
||||
using mRemoteNG.Config.MachineIdentifier;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
public class LocalSettingsDBManager
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class LocalDBManager
|
||||
{
|
||||
private readonly string _dbPath;
|
||||
private readonly string _schemaPath;
|
||||
@@ -21,12 +23,31 @@ public class LocalSettingsDBManager
|
||||
/// <param name="dbPath">The path to the database file.</param>
|
||||
/// <param name="useEncryption">Indicates whether to use encryption for the database. If null, no change is made to an existing database.</param>
|
||||
/// <param name="schemaFilePath">Optional path to a schema file for creating the database structure.</param>
|
||||
public LocalSettingsDBManager(string dbPath = null, bool? useEncryption = null, string schemaFilePath = null)
|
||||
public LocalDBManager(string dbPath = null, bool? useEncryption = null, string schemaFilePath = null)
|
||||
{
|
||||
_dbPath = string.IsNullOrWhiteSpace(dbPath) ? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "mRemoteNG.appSettings") : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, dbPath);
|
||||
_schemaPath = string.IsNullOrWhiteSpace(schemaFilePath) ? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Schemas\\mremoteng_default_settings_v1_0.json") : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, schemaFilePath);
|
||||
_useEncryption = useEncryption;
|
||||
_mRIdentifier = Convert.ToBase64String(System.Security.Cryptography.SHA256.Create().ComputeHash(System.Text.Encoding.UTF8.GetBytes(GetDiskIdentifier() + "_" + Environment.MachineName)));
|
||||
|
||||
/// <summary>
|
||||
/// Generate a unique identifier for the machine
|
||||
/// </summary>
|
||||
|
||||
try
|
||||
{
|
||||
// Generate the machine identifier
|
||||
_mRIdentifier = MachineIdentifierGenerator.GenerateMachineIdentifier();
|
||||
Console.WriteLine($"Generated Identifier: {_mRIdentifier}");
|
||||
}
|
||||
catch (PlatformNotSupportedException ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"An error occurred: {ex.Message}");
|
||||
}
|
||||
|
||||
|
||||
// Check if disk identifier is empty and prevent database creation if true
|
||||
if (string.IsNullOrEmpty(_mRIdentifier))
|
||||
@@ -53,6 +74,7 @@ public class LocalSettingsDBManager
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Ensures default settings are imported if the database is empty.
|
||||
/// </summary>
|
||||
@@ -111,6 +133,10 @@ public class LocalSettingsDBManager
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(schemaFilePath) && File.Exists(schemaFilePath))
|
||||
{
|
||||
if (schemaFilePath == null || schemaFilePath.Contains("../") || schemaFilePath.Contains(@"..\"))
|
||||
{
|
||||
throw new ArgumentException("Invalid file path");
|
||||
}
|
||||
var schemaJson = File.ReadAllText(schemaFilePath);
|
||||
using (JsonDocument doc = JsonDocument.Parse(schemaJson))
|
||||
{
|
||||
@@ -247,6 +273,10 @@ public void EncryptDatabase()
|
||||
{
|
||||
if (File.Exists(jsonFilePath))
|
||||
{
|
||||
if (jsonFilePath == null || jsonFilePath.Contains("../") || jsonFilePath.Contains(@"..\"))
|
||||
{
|
||||
throw new ArgumentException("Invalid file path");
|
||||
}
|
||||
var json = File.ReadAllText(jsonFilePath);
|
||||
var settingsData = JsonSerializer.Deserialize<Dictionary<string, List<Setting>>>(json);
|
||||
|
||||
@@ -286,6 +316,10 @@ public void EncryptDatabase()
|
||||
}
|
||||
|
||||
var json = JsonSerializer.Serialize(settingsData, new JsonSerializerOptions { WriteIndented = true });
|
||||
if (jsonFilePath == null || jsonFilePath.Contains("../") || jsonFilePath.Contains(@"..\"))
|
||||
{
|
||||
throw new ArgumentException("Invalid file path");
|
||||
}
|
||||
File.WriteAllText(jsonFilePath, json);
|
||||
Console.WriteLine("Settings successfully exported to JSON file.");
|
||||
}
|
||||
@@ -369,42 +403,6 @@ public void EncryptDatabase()
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique machine identifier (serial number of the hard drive) combined with the machine name and encrypts it using SHA256.
|
||||
/// </summary>
|
||||
/// <returns>Unique machine identifier.</returns>
|
||||
private static string GetDiskIdentifier()
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Use ManagementObject to get the serial number of the hard drive
|
||||
using (var searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_DiskDrive"))
|
||||
{
|
||||
foreach (var disk in searcher.Get())
|
||||
{
|
||||
string sn = "" + disk["SerialNumber"]; // 2025-01-14 in .net8 this returns NULL in virtual machines
|
||||
return sn.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error getting disk identifier: {ex.Message}");
|
||||
throw new InvalidOperationException("Failed to retrieve disk identifier. Please ensure the disk information is accessible.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new PlatformNotSupportedException("This method is only supported on Windows.");
|
||||
}
|
||||
|
||||
// Return an empty string if no serial number is found
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Setting class
|
||||
public class Setting
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// The MIT License (MIT)
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright(c) crdx
|
||||
//
|
||||
@@ -31,6 +31,7 @@ using System.Windows.Forms;
|
||||
using System.Collections.Specialized;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using mRemoteNG.Security;
|
||||
|
||||
//using mRemoteNG.App;
|
||||
|
||||
@@ -61,8 +62,7 @@ namespace mRemoteNG.Config.Settings.Providers
|
||||
if (_xmlDocument != null) return _xmlDocument;
|
||||
try
|
||||
{
|
||||
_xmlDocument = new XmlDocument();
|
||||
_xmlDocument.Load(_filePath);
|
||||
_xmlDocument = SecureXmlHelper.LoadXmlFromFile(_filePath);
|
||||
}
|
||||
catch (Exception /*ex*/)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
@@ -14,7 +15,7 @@ using System.Security;
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public abstract class AbstractConnectionRecord : INotifyPropertyChanged
|
||||
public abstract class AbstractConnectionRecord(string uniqueId) : INotifyPropertyChanged
|
||||
{
|
||||
#region Fields
|
||||
|
||||
@@ -22,6 +23,8 @@ namespace mRemoteNG.Connection
|
||||
private string _description;
|
||||
private string _icon;
|
||||
private string _panel;
|
||||
private string _color;
|
||||
private string _tabColor;
|
||||
|
||||
private string _hostname;
|
||||
private ExternalAddressProvider _externalAddressProvider;
|
||||
@@ -30,14 +33,15 @@ namespace mRemoteNG.Connection
|
||||
private ExternalCredentialProvider _externalCredentialProvider;
|
||||
private string _userViaAPI = "";
|
||||
private string _username = "";
|
||||
private SecureString _password = null;
|
||||
//private SecureString _password = null;
|
||||
private string _password = null;
|
||||
private string _domain = "";
|
||||
private string _vmId = "";
|
||||
private bool _useEnhancedMode;
|
||||
|
||||
private string _sshTunnelConnectionName = "";
|
||||
private ProtocolType _protocol;
|
||||
private RdpVersion _rdpProtocolVersion;
|
||||
private RdpVersion _rdpProtocolVersion = RdpVersion.Rdc10;
|
||||
private string _extApp;
|
||||
private int _port;
|
||||
private string _sshOptions = "";
|
||||
@@ -152,6 +156,28 @@ namespace mRemoteNG.Connection
|
||||
set => SetField(ref _panel, value, "Panel");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Display)),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Color)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionColor)),
|
||||
Editor(typeof(System.Drawing.Design.ColorEditor), typeof(System.Drawing.Design.UITypeEditor)),
|
||||
TypeConverter(typeof(MiscTools.TabColorConverter))]
|
||||
public virtual string Color
|
||||
{
|
||||
get => GetPropertyValue("Color", _color);
|
||||
set => SetField(ref _color, value, "Color");
|
||||
}
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Display)),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.TabColor)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionTabColor)),
|
||||
Editor(typeof(System.Drawing.Design.ColorEditor), typeof(System.Drawing.Design.UITypeEditor)),
|
||||
TypeConverter(typeof(MiscTools.TabColorConverter))]
|
||||
public virtual string TabColor
|
||||
{
|
||||
get => GetPropertyValue("TabColor", _tabColor);
|
||||
set => SetField(ref _tabColor, value, "TabColor");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Connection
|
||||
@@ -202,7 +228,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Connection), 2),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Username)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionUsername)),
|
||||
AttributeUsedInProtocol(ProtocolType.RDP, ProtocolType.SSH1, ProtocolType.SSH2)]
|
||||
AttributeUsedInProtocol(ProtocolType.RDP, ProtocolType.SSH1, ProtocolType.SSH2, ProtocolType.HTTP, ProtocolType.HTTPS, ProtocolType.IntApp)]
|
||||
public virtual string Username
|
||||
{
|
||||
get => GetPropertyValue("Username", _username);
|
||||
@@ -214,7 +240,8 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionPassword)),
|
||||
PasswordPropertyText(true),
|
||||
AttributeUsedInAllProtocolsExcept(ProtocolType.Telnet, ProtocolType.Rlogin, ProtocolType.RAW)]
|
||||
public virtual SecureString Password
|
||||
//public virtual SecureString Password
|
||||
public virtual string Password
|
||||
{
|
||||
get => GetPropertyValue("Password", _password);
|
||||
set => SetField(ref _password, value, "Password");
|
||||
@@ -827,7 +854,7 @@ namespace mRemoteNG.Connection
|
||||
|
||||
#region Misc
|
||||
|
||||
[Browsable(false)] public string ConstantID { get; }
|
||||
[Browsable(false)] public string ConstantID { get; } = uniqueId.ThrowIfNullOrEmpty(nameof(uniqueId));
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Miscellaneous), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ExternalToolBefore)),
|
||||
@@ -906,7 +933,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Compression)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionCompression)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.Compression VNCCompression
|
||||
{
|
||||
@@ -918,7 +945,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Encoding)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionEncoding)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.Encoding VNCEncoding
|
||||
{
|
||||
@@ -930,7 +957,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.AuthenticationMode)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionAuthenticationMode)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.AuthMode VNCAuthMode
|
||||
{
|
||||
@@ -942,7 +969,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyType)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyType)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.ProxyType VNCProxyType
|
||||
{
|
||||
@@ -953,7 +980,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Proxy), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyAddress)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyAddress)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public string VNCProxyIP
|
||||
{
|
||||
@@ -964,7 +991,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Proxy), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyPort)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyPort)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public int VNCProxyPort
|
||||
{
|
||||
@@ -975,7 +1002,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Proxy), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyUsername)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyUsername)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public string VNCProxyUsername
|
||||
{
|
||||
@@ -987,7 +1014,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyPassword)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyPassword)),
|
||||
PasswordPropertyText(true),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public string VNCProxyPassword
|
||||
{
|
||||
@@ -999,7 +1026,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Colors)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionColors)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.Colors VNCColors
|
||||
{
|
||||
@@ -1011,7 +1038,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.SmartSizeMode)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionSmartSizeMode)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC)]
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD)]
|
||||
public ProtocolVNC.SmartSizeMode VNCSmartSizeMode
|
||||
{
|
||||
get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode);
|
||||
@@ -1022,7 +1049,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ViewOnly)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionViewOnly)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC)]
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD)]
|
||||
public bool VNCViewOnly
|
||||
{
|
||||
get => GetPropertyValue("VNCViewOnly", _vncViewOnly);
|
||||
@@ -1030,20 +1057,14 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
protected AbstractConnectionRecord(string uniqueId)
|
||||
{
|
||||
ConstantID = uniqueId.ThrowIfNullOrEmpty(nameof(uniqueId));
|
||||
}
|
||||
|
||||
protected virtual TPropertyType GetPropertyValue<TPropertyType>(string propertyName, TPropertyType value)
|
||||
{
|
||||
return (TPropertyType)GetType().GetProperty(propertyName)?.GetValue(this, null);
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected virtual void RaisePropertyChangedEvent(object sender, PropertyChangedEventArgs args)
|
||||
{
|
||||
|
||||
@@ -12,22 +12,22 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
public static string[] Icons = { };
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
|
||||
{
|
||||
return new StandardValuesCollection(Icons);
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static System.Drawing.Icon FromString(string iconName)
|
||||
public static System.Drawing.Icon? FromString(string iconName)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -41,7 +41,7 @@ namespace mRemoteNG.Connection
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, $"Couldn\'t get Icon from String" + Environment.NewLine + ex.Message);
|
||||
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, $"Couldn't get Icon from String" + Environment.NewLine + ex.Message);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.ARD;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.PowerShell;
|
||||
using mRemoteNG.Connection.Protocol.RAW;
|
||||
@@ -254,6 +255,8 @@ namespace mRemoteNG.Connection
|
||||
return (int)RdpProtocol.Defaults.Port;
|
||||
case ProtocolType.VNC:
|
||||
return (int)ProtocolVNC.Defaults.Port;
|
||||
case ProtocolType.ARD:
|
||||
return (int)ProtocolARD.Defaults.Port;
|
||||
case ProtocolType.SSH1:
|
||||
return (int)ProtocolSSH1.Defaults.Port;
|
||||
case ProtocolType.SSH2:
|
||||
@@ -289,6 +292,8 @@ namespace mRemoteNG.Connection
|
||||
Description = Settings.Default.ConDefaultDescription;
|
||||
Icon = Settings.Default.ConDefaultIcon;
|
||||
Panel = Language.General;
|
||||
Color = string.Empty;
|
||||
TabColor = string.Empty;
|
||||
}
|
||||
|
||||
private void SetConnectionDefaults()
|
||||
|
||||
@@ -6,18 +6,17 @@ using System.Runtime.Versioning;
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ConnectionInfoComparer<TProperty> : IComparer<ConnectionInfo> where TProperty : IComparable<TProperty>
|
||||
public class ConnectionInfoComparer<TProperty>(Func<ConnectionInfo, TProperty> sortExpression) : IComparer<ConnectionInfo> where TProperty : IComparable<TProperty>
|
||||
{
|
||||
private readonly Func<ConnectionInfo, TProperty> _sortExpression;
|
||||
private readonly Func<ConnectionInfo, TProperty> _sortExpression = sortExpression;
|
||||
public ListSortDirection SortDirection { get; set; } = ListSortDirection.Ascending;
|
||||
|
||||
public ConnectionInfoComparer(Func<ConnectionInfo, TProperty> sortExpression)
|
||||
public int Compare(ConnectionInfo? x, ConnectionInfo? y)
|
||||
{
|
||||
_sortExpression = sortExpression;
|
||||
}
|
||||
if (x == null && y == null) return 0;
|
||||
if (x == null) return SortDirection == ListSortDirection.Ascending ? -1 : 1;
|
||||
if (y == null) return SortDirection == ListSortDirection.Ascending ? 1 : -1;
|
||||
|
||||
public int Compare(ConnectionInfo x, ConnectionInfo y)
|
||||
{
|
||||
return SortDirection == ListSortDirection.Ascending ? CompareAscending(x, y) : CompareDescending(x, y);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,18 @@ namespace mRemoteNG.Connection
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool Panel { get; set; }
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Display), 2),
|
||||
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.Color)),
|
||||
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionColor)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool Color { get; set; }
|
||||
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Display), 2),
|
||||
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.TabColor)),
|
||||
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionTabColor)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool TabColor { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Connection
|
||||
|
||||
@@ -406,21 +406,16 @@ namespace mRemoteNG.Connection
|
||||
try
|
||||
{
|
||||
ProtocolBase prot = (ProtocolBase)sender;
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.ConnenctionCloseEvent,
|
||||
true);
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.ConnenctionCloseEvent, true);
|
||||
string connDetail;
|
||||
if (prot.InterfaceControl.OriginalInfo.Hostname == "" &&
|
||||
prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp)
|
||||
if (prot.InterfaceControl.OriginalInfo.Hostname == "" && prot.InterfaceControl.Info.Protocol == ProtocolType.IntApp)
|
||||
connDetail = prot.InterfaceControl.Info.ExtApp;
|
||||
else if (prot.InterfaceControl.OriginalInfo.Hostname != "")
|
||||
connDetail = prot.InterfaceControl.OriginalInfo.Hostname;
|
||||
else
|
||||
connDetail = "UNKNOWN";
|
||||
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
|
||||
string.Format(Language.ConnenctionClosedByUser, connDetail,
|
||||
prot.InterfaceControl.Info.Protocol,
|
||||
Environment.UserName));
|
||||
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.ConnenctionClosedByUser, connDetail, prot.InterfaceControl.Info.Protocol, Environment.UserName));
|
||||
prot.InterfaceControl.OriginalInfo.OpenConnections.Remove(prot);
|
||||
if (_activeConnections.Contains(prot.InterfaceControl.Info.ConstantID))
|
||||
_activeConnections.Remove(prot.InterfaceControl.Info.ConstantID);
|
||||
|
||||
@@ -23,12 +23,12 @@ using mRemoteNG.Config.Serializers.ConnectionSerializers.Sql;
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ConnectionsService
|
||||
public class ConnectionsService(PuttySessionsManager puttySessionsManager)
|
||||
{
|
||||
private static readonly object SaveLock = new();
|
||||
private readonly PuttySessionsManager _puttySessionsManager;
|
||||
private readonly IDataProvider<string> _localConnectionPropertiesDataProvider;
|
||||
private readonly LocalConnectionPropertiesXmlSerializer _localConnectionPropertiesSerializer;
|
||||
private readonly PuttySessionsManager _puttySessionsManager = puttySessionsManager ?? throw new ArgumentNullException(nameof(puttySessionsManager));
|
||||
private readonly IDataProvider<string> _localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(SettingsFileInfo.SettingsPath, SettingsFileInfo.LocalConnectionProperties));
|
||||
private readonly LocalConnectionPropertiesXmlSerializer _localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
|
||||
private bool _batchingSaves = false;
|
||||
private bool _saveRequested = false;
|
||||
private bool _saveAsyncRequested = false;
|
||||
@@ -42,13 +42,6 @@ namespace mRemoteNG.Connection
|
||||
|
||||
public ConnectionTreeModel ConnectionTreeModel { get; private set; }
|
||||
|
||||
public ConnectionsService(PuttySessionsManager puttySessionsManager)
|
||||
{
|
||||
_puttySessionsManager = puttySessionsManager ?? throw new ArgumentNullException(nameof(puttySessionsManager));
|
||||
_localConnectionPropertiesDataProvider = new FileDataProvider(Path.Combine(SettingsFileInfo.SettingsPath, SettingsFileInfo.LocalConnectionProperties));
|
||||
_localConnectionPropertiesSerializer = new LocalConnectionPropertiesXmlSerializer();
|
||||
}
|
||||
|
||||
public void NewConnectionsFile(string filename)
|
||||
{
|
||||
try
|
||||
|
||||
19
mRemoteNG/Connection/InterfaceControl.Designer.cs
generated
19
mRemoteNG/Connection/InterfaceControl.Designer.cs
generated
@@ -1,4 +1,4 @@
|
||||
namespace mRemoteNG.Connection
|
||||
namespace mRemoteNG.Connection
|
||||
{
|
||||
public sealed partial class InterfaceControl : System.Windows.Forms.Panel
|
||||
{
|
||||
@@ -21,14 +21,11 @@ namespace mRemoteNG.Connection
|
||||
|
||||
//Required by the Windows Form Designer
|
||||
private System.ComponentModel.Container components = null;
|
||||
|
||||
//NOTE: The following procedure is required by the Windows Form Designer
|
||||
//It can be modified using the Windows Form Designer.
|
||||
//Do not modify it using the code editor.
|
||||
[System.Diagnostics.DebuggerStepThrough()]
|
||||
private void InitializeComponent()
|
||||
{
|
||||
components = new System.ComponentModel.Container();
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: The following procedure is required by the Windows Form Designer
|
||||
//It can be modified using the Windows Form Designer.
|
||||
//Do not modify it using the code editor.
|
||||
[System.Diagnostics.DebuggerStepThrough()]
|
||||
private void InitializeComponent() => components = new System.ComponentModel.Container();
|
||||
}
|
||||
}
|
||||
|
||||
19
mRemoteNG/Connection/Protocol/ARD/ProtocolARD.cs
Normal file
19
mRemoteNG/Connection/Protocol/ARD/ProtocolARD.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.ARD
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ProtocolARD : ProtocolVNC
|
||||
{
|
||||
public ProtocolARD()
|
||||
{
|
||||
}
|
||||
|
||||
public new enum Defaults
|
||||
{
|
||||
Port = 5900
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using mRemoteNG.Connection.Protocol.Rlogin;
|
||||
using mRemoteNG.Connection.Protocol.SSH;
|
||||
using mRemoteNG.Connection.Protocol.Telnet;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Connection.Protocol.ARD;
|
||||
using System;
|
||||
using mRemoteNG.Connection.Protocol.PowerShell;
|
||||
using mRemoteNG.Resources.Language;
|
||||
@@ -28,6 +29,8 @@ namespace mRemoteNG.Connection.Protocol
|
||||
return rdp;
|
||||
case ProtocolType.VNC:
|
||||
return new ProtocolVNC();
|
||||
case ProtocolType.ARD:
|
||||
return new ProtocolARD();
|
||||
case ProtocolType.SSH1:
|
||||
return new ProtocolSSH1();
|
||||
case ProtocolType.SSH2:
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
// ReSharper disable ArrangeAccessorOwnerBody
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ProtocolList : CollectionBase, INotifyCollectionChanged
|
||||
{
|
||||
public ProtocolBase this[object index]
|
||||
@@ -23,7 +25,6 @@ namespace mRemoteNG.Connection.Protocol
|
||||
|
||||
public new int Count => List.Count;
|
||||
|
||||
|
||||
public void Add(ProtocolBase cProt)
|
||||
{
|
||||
List.Add(cProt);
|
||||
@@ -64,7 +65,7 @@ namespace mRemoteNG.Connection.Protocol
|
||||
RaiseCollectionChangedEvent(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||
}
|
||||
|
||||
public event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged; // Fix for CS8612: Declare the event as nullable to match the interface.
|
||||
|
||||
private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace mRemoteNG.Connection.Protocol
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.PowerShell))]
|
||||
PowerShell = 10,
|
||||
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.Ard))]
|
||||
ARD = 11,
|
||||
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.ExternalTool))]
|
||||
IntApp = 20
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user