Compare commits

..

176 Commits

Author SHA1 Message Date
David Sparer
5ce8171f12 updated changelog 2017-11-01 15:29:54 -05:00
David Sparer
e3121cb043 bumped assembly version 2017-11-01 15:14:55 -05:00
David Sparer
99e52ab0b5 updated changelog 2017-10-31 15:08:06 -05:00
David Sparer
2b672dc4fc Fixed another minor issue with external tools 2017-10-31 14:07:18 -05:00
David Sparer
6db7adf900 re-implemented autoresizecolumn in the connection tree
I did this in order to get around a weird bug where the connection tree would sometimes be set to a very small width (making it not visible)
2017-10-31 13:10:49 -05:00
David Sparer
65782285a3 added a few unit tests for integrated programs 2017-10-31 09:56:48 -05:00
David Sparer
64bd5a93ad resolves #761 2017-10-31 08:11:57 -05:00
David Sparer
68f052efcb Merge branch 'hotfix10' 2017-10-29 12:44:53 -05:00
David Sparer
4a8baf79fb bumped assembly version 2017-10-29 12:44:18 -05:00
David Sparer
499ac0295e fixed one case where visible connection tree width wasnt being updated correctly 2017-10-29 12:33:29 -05:00
David Sparer
29c422501a resolves #756 2017-10-29 12:17:18 -05:00
David Sparer
8efe74f614 bump assembly version 2017-10-28 16:25:08 -05:00
David Sparer
4e0f12f4b9 Merge branch 'Patch9' 2017-10-28 15:55:09 -05:00
David Sparer
cbd3a61259 updated changelog and credits 2017-10-28 15:48:16 -05:00
David Sparer
2406a7be49 fixes #600 2017-10-28 15:12:30 -05:00
David Sparer
dd40b56047 Merge pull request #728 from dekelMP/Patch9
Fixed #529
2017-10-27 18:55:22 -05:00
Sean Kaim
f14a0d5ee3 Merge pull request #710 from pedro2555/issue#649-cannot-integrate-cli-apps
Fixed integrated cli apps?
2017-10-19 09:54:07 -04:00
Dekel Asaf
e0383d6c59 Fixed #529 2017-09-22 20:57:46 +03:00
Pedro Rodrigues
eeabcd94ed re-removed WaitForInputIdle
later consideration
2017-09-19 23:07:55 +01:00
Sean Kaim
8a3e37041a remove unnecessary converts 2017-09-18 17:37:04 -04:00
Sean Kaim
a1e9aefeb2 Merge branch 'Patch9' of https://github.com/mRemoteNG/mRemoteNG into Patch9 2017-09-18 10:02:09 -04:00
Sean Kaim
670cb51352 unnecessary convert.tostring's 2017-09-18 10:02:07 -04:00
Sean Kaim
a43dff88c5 Merge pull request #715 from pedro2555/492
fallback to empty credentials settings in external apps
2017-09-18 09:58:24 -04:00
David Sparer
fb3c87359f Merge pull request #724 from mRemoteNG/482_proposed_fix
Default connection password must be decrypted before first use
2017-09-18 08:48:06 -05:00
kmscode
a49dec7e6d just claify a comment. 2017-09-17 14:57:56 -04:00
kmscode
a7156235c3 puttyng 0.70
fixes #635
2017-09-17 14:22:36 -04:00
David Sparer
3cb52ba3f1 rearranged program init to ensure ConDefaultPassword is decrypted before assignment to DefaultConnectionInfo object 2017-09-17 11:10:32 -05:00
Sean Kaim
024f1a7047 minor code clean up 2017-09-15 17:37:28 -04:00
Sean Kaim
b77c7e922f Merge pull request #720 from pedro2555/676
First startup ignores cons param
2017-09-15 17:33:22 -04:00
Sean Kaim
9335c4706b fix editbin post build on jenkins 2017-09-15 16:52:42 -04:00
Sean Kaim
e09a9dabd6 update nuget packages 2017-09-15 15:42:28 -04:00
Pedro Rodrigues
e4e2f50015 Saving settings before exiting, and avoid early return 2017-09-15 20:38:34 +01:00
Sean Kaim
61865050c7 minor code cleanup 2017-09-15 15:34:54 -04:00
Sean Kaim
05d90c26ff Merge pull request #709 from pedro2555/issue#335
Changed quick connect connection icon image to play icon when there a…
2017-09-15 15:31:16 -04:00
Sean Kaim
43cdb29eb6 we don't need to look in ProgramData 2017-09-15 15:28:29 -04:00
Pedro Rodrigues
87ff1cb2b2 preparing ConsParam, and use Path.Combine in favor of string concatenation 2017-09-15 19:36:00 +01:00
Pedro Rodrigues
f73c9c9d02 Refactored cons param, corrected fallback override on first initialization.
Fixes 676
2017-09-15 19:17:08 +01:00
Sean Kaim
d15e444cb7 code clean up / null checks & logging 2017-09-15 13:58:32 -04:00
Pedro Rodrigues
2eff6c3dc4 if ( == false) is confusing, no need for it, if no else then ! 2017-09-15 18:49:06 +01:00
David Sparer
41fe211aec resolved #610 2017-09-15 08:07:12 -05:00
David Sparer
2acfa6d88d added another valid MS certificate thumbprint for build tools 2017-09-14 14:57:40 -05:00
Pedro Rodrigues
348b0c728c fallback to empty credentials settings in external apps #492 2017-09-14 20:16:53 +01:00
Pedro Rodrigues
875e1573a4 Fixed integrated cli apps?
What was WaitForInputIdle() then?
2017-09-11 01:01:18 +01:00
Pedro Rodrigues
926dc868ef Changed quick connect connection icon image to play icon when there are open connections 2017-09-10 22:42:29 +01:00
kmscode
86ecb38ae2 minor code cleanup 2017-09-09 15:36:53 -04:00
Sean Kaim
f3ca58111c Merge pull request #705 from pedro2555/fix-proposal-issue#665
Fix proposal for issue 'Can not add new connection or new folder'
2017-09-09 15:34:44 -04:00
kmscode
3124d3ca1c minor code cleanup 2017-09-09 15:10:33 -04:00
Sean Kaim
9012506209 Merge pull request #700 from pedro2555/fix-write-log-file-option
Prevented log file creation when writeLogFile option is not set
2017-09-09 15:01:06 -04:00
kmscode
adb874ca74 avoid writing to the log when configured not to
plus some minor optimization.
2017-09-09 14:59:42 -04:00
kmscode
6aaf2f031b find editbin for vs 2017 community
updated acceptable authenticode for editbin.
2017-09-09 14:26:38 -04:00
Pedro Rodrigues
1669377938 Use root node when creating new connection/folder and no node is selected 2017-09-09 17:17:23 +01:00
Pedro Rodrigues
198c235765 Prevent log file writing when option is not set 2017-09-06 22:19:32 +01:00
David Sparer
66f2c55343 Merge remote-tracking branch 'origin/master' into Patch9 2017-08-10 17:19:29 -05:00
David Sparer
0f3fa86bed Merge pull request #677 from mRemoteNG/improve_publish_automation
Improve publish automation
2017-08-10 17:18:19 -05:00
David Sparer
e5c2cfd243 fix github release body builder function 2017-08-10 16:35:17 -05:00
David Sparer
ef1c397f11 updated changelog 2017-08-05 11:02:16 -05:00
David Sparer
12e0cc3d7b Merge pull request #652 from mrwulf/Issue550
Issue #550 Fix - Don't propagate edit if it didn't come from the menu item
2017-08-05 10:59:06 -05:00
David Sparer
ff6bb6ebb0 update changelog and credits 2017-08-05 10:52:36 -05:00
David Sparer
6b78215b2e Merge pull request #651 from mrwulf/Issue176
Only do ActivateConnection when one of our known controls wasn't clicked (Addresses Issue #176)
2017-08-05 10:45:16 -05:00
Sean Kaim
5d9a02657f Fixes #658
Also fix a comment.
2017-07-28 15:25:56 -04:00
Brandon Wulf
14d670a9a2 Don't propagate edit if it didn't come from the menu item 2017-07-21 15:38:46 -07:00
Brandon Wulf
67801506e0 Only do ActivateConnection when one of our known controls wasn't clicked. 2017-07-21 14:19:08 -07:00
Sean Kaim
48eb6dbbe0 updated changelog 2017-07-18 15:13:48 -04:00
Sean Kaim
d520c6a816 Exception after clicking on import port scan
Fixes #646
2017-07-18 14:31:21 -04:00
David Sparer
664799c01b minor fix to allow building on some older machines
Oder editbin.exe files from Microsoft were signed with a different cert thumbprint. This update makes it easier to add additional valid thumbprints for MS signed tools
2017-06-27 12:20:39 -05:00
David Sparer
d88c5b9db2 minor error message correction
changed an error message that referred to File -> Load Connections (which doesn't exist). Changed this to File -> Open Connection File
2017-06-27 12:15:38 -05:00
Sean Kaim
0fe7a693f8 changelog 2017-06-16 10:08:04 -04:00
Sean Kaim
9a2efd9686 Exception launching ExtTool without con selected 2017-06-16 09:54:52 -04:00
Sean Kaim
88961fbdb5 Merge pull request #593 from mRemoteNG/kmscode-patch-1
changelog update
2017-06-15 15:02:20 -04:00
Sean Kaim
a11ceced09 changelog update 2017-06-15 15:00:34 -04:00
Sean Kaim
ca35662ca2 Merge pull request #592 from mRemoteNG/hotfix7
Hotfix8
2017-06-15 11:52:59 -04:00
Sean Kaim
e7c4bbe1e8 increment version 2017-06-15 11:33:50 -04:00
Sean Kaim
1bc56b5c9e Merge remote-tracking branch 'refs/remotes/origin/master' into hotfix7 2017-06-15 11:29:55 -04:00
Sean Kaim
25a0630bcb updated putty build
New version number: 0.69.0.1

Fixes #589
2017-06-15 11:28:41 -04:00
Sean Kaim
1f7d122bee clean up installer build a bit 2017-06-15 11:19:30 -04:00
Sean Kaim
d9cb32ca53 enable verbose logging within the MSI 2017-06-15 11:19:02 -04:00
David Sparer
760587ee2e Merge pull request #590 from mRemoteNG/update_jenkinsfile
jenkins release builds will now clean then build
2017-06-14 11:21:21 -05:00
David Sparer
d2fe8a2ddb builds will now clean then build 2017-06-14 11:14:36 -05:00
Sean Kaim
81b0be0489 Merge pull request #588 from mRemoteNG/hotfix7
Hotfix7 changelog
2017-06-14 11:10:19 -04:00
Sean Kaim
3074a211f8 changelog 2017-06-14 11:08:55 -04:00
Sean Kaim
0659b140f5 Merge pull request #587 from mRemoteNG/hotfix7
Hotfix7
2017-06-14 10:59:06 -04:00
Sean Kaim
0b8160ae34 changelog 2017-06-14 10:57:49 -04:00
Sean Kaim
dbf2b7b4b6 increment version 2017-06-14 10:51:24 -04:00
Sean Kaim
1e8afc8ea4 update readme 2017-06-14 10:48:57 -04:00
Sean Kaim
70bd2e8a78 rebuilt & signed puttyng 0.69 2017-06-14 10:48:46 -04:00
Sean Kaim
8045544051 Merge pull request #581 from mRemoteNG/hotfix6
Hotfix6
2017-06-13 11:15:08 -04:00
Sean Kaim
0cef4dc9b3 changelog update 2017-06-13 10:49:05 -04:00
Sean Kaim
f1cfa4330a fix build/porting problem for about window 2017-06-13 10:42:31 -04:00
Sean Kaim
a50b370262 Use all space on about page
Fixed 377
9c5e4f7a7c
2017-06-13 10:24:40 -04:00
Sean Kaim
064fd217ba initial Hotfix 6 commit 2017-06-02 16:45:23 -04:00
David Sparer
692b26622c Merge pull request #534 from mRemoteNG/530_fix_tree_node_entry_creation_on_exttool_run
530 fix tree node entry creation on exttool run
2017-05-02 10:00:30 -06:00
David Sparer
72a56d33d0 updated changelog 2017-05-02 09:08:49 -06:00
David Sparer
ce4bfc55c1 ConnectionInfo.Clone no longer sets the Parent property
this resolves undesirable tree nodes from being created
2017-05-02 08:49:04 -06:00
David Sparer
f0faec9def Merge pull request #528 from mRemoteNG/hotfix5
1.75 Hotfix5
2017-04-27 15:36:16 -06:00
David Sparer
e6ef28050c set release date in changelog for 1.75.7005 2017-04-27 15:20:07 -06:00
David Sparer
547ec3cb3a updated msi installer requirements
Replaced KB2923545 with KB2830477 (which is the REAL rdp 8.1 update)
2017-04-25 21:06:25 -06:00
David Sparer
fc0f278962 signed putty v0.68 exe 2017-04-20 09:27:14 -06:00
David Sparer
1f3db15892 Merge branch '442_fix_importing_putty_session_with_spaces_in_name' into hotfix5 2017-04-20 09:17:22 -06:00
David Sparer
e3e4c49427 changelog update 2017-04-20 09:16:31 -06:00
David Sparer
1520b8bf73 fixed bug where any sessions with spaces in the name would be filtered out
this fixes the bug, but the entire putty sessions loading component should be refactored heavily
2017-04-20 09:07:21 -06:00
David Sparer
c9e7f82905 fixed minor bug with adding a duplicate default session in some situations 2017-04-20 08:53:57 -06:00
Sean Kaim
d2357fa779 changelog update 2017-04-19 12:38:54 -04:00
Sean Kaim
703178ddf1 Fix NPE when importing from the connection tree
Fixes #518
2017-04-19 12:37:56 -04:00
Sean Kaim
4e9c5de16c changelog 2017-04-17 17:34:09 -04:00
Sean Kaim
3d1fcc35df Update credits.txt 2017-04-17 17:30:14 -04:00
Sean Kaim
e20d7afb72 update changelog 2017-04-17 17:29:32 -04:00
Sean Kaim
07e2bc3858 update change log 2017-04-17 11:56:47 -04:00
Sean Kaim
f3b11d6f72 Fix for #434 - SysTray SafeHandle 2017-04-14 17:25:40 -04:00
Sean Kaim
69f310c02c PuTTYNG.exe 0.68 2017-04-14 17:00:22 -04:00
Sean Kaim
3308f1146c load expanded data properly
and minor optimization
2017-04-14 15:50:20 -04:00
Sean Kaim
8e8cf3df8d check for nulls 2017-04-14 15:34:55 -04:00
Sean Kaim
26fdd924ef Increment version number
And make it match the hotfix number - you have no idea how much that was
annoying me...
2017-04-14 14:44:26 -04:00
Sean Kaim
ea3494f6e7 Merge pull request #512 from mRemoteNG/483_make_datatable_serializer_safer
483 make datatable serializer safer
2017-04-14 14:37:33 -04:00
David Sparer
9f028d9104 added some safety checking for data table deserialization
added some tests for the data table deserializer
2017-04-09 17:36:56 -06:00
David Sparer
f40be696c7 made utility for creating test connection tree models 2017-04-09 17:35:52 -06:00
David Sparer
95a503a390 fix issue with setting up data table 2017-04-09 17:05:36 -06:00
David Sparer
88c51f4933 added some safety checks to the data table serialier 2017-04-09 16:57:56 -06:00
David Sparer
9e20f1dd33 created script for publishing a github release that is currently in draft mode 2017-03-24 18:08:27 -06:00
David Sparer
16be19b5d3 split github functions to a library script 2017-03-24 18:07:23 -06:00
David Sparer
80ac0259b8 fix script name 2017-03-24 16:50:15 -06:00
David Sparer
9f7911923c updated the create_upg_check_files script to be parameterized for use within jenkins 2017-03-24 16:40:41 -06:00
David Sparer
686005071e Merge branch 'resolve_sql_deserialization_issue' 2017-03-24 15:26:28 -06:00
David Sparer
e16d31d605 fixed stupid transposition typo 2017-03-24 15:14:57 -06:00
David Sparer
8b201d22cb added authkey requirement to get-githubrelease in order to show drafts 2017-03-24 15:07:31 -06:00
David Sparer
0f6f8d43bd added cmdlet for retrieving a github release 2017-03-24 14:28:18 -06:00
David Sparer
8f171cddd9 fix content type of msi upload to github 2017-03-24 14:23:38 -06:00
David Sparer
c77c323f73 fix jenkinsfile variable 2017-03-24 14:22:17 -06:00
David Sparer
9e358309e4 Merge branch 'master' into resolve_sql_deserialization_issue 2017-03-24 12:14:26 -06:00
David Sparer
485438f38d Merge pull request #472 from mRemoteNG/fix_jenkinsfile_publish
fixed hard coded branch names in jenkinsfile_publish
2017-03-24 12:06:55 -06:00
David Sparer
fe26a60337 fixed hard coded branch names in jenkinsfile_publish 2017-03-24 12:04:52 -06:00
David Sparer
d2c2de4dd7 Merge branch 'master' into resolve_sql_deserialization_issue 2017-03-24 11:42:01 -06:00
David Sparer
d49d58f7f8 fixed parent reference update issue in mRemoteNGImporter 2017-03-24 11:40:28 -06:00
David Sparer
164d4fff8b Merge pull request #470 from mRemoteNG/pipeline_tests
Create jenkins pipeline script for release automation
2017-03-23 16:46:13 -06:00
David Sparer
7726406674 added loggers to the test runners 2017-03-23 09:40:31 -06:00
David Sparer
ed38b39fec attempting to resolve bug with accessing correct key store 2017-03-23 08:59:09 -06:00
David Sparer
9188d4316e fix variable issue 2017-03-23 08:52:24 -06:00
David Sparer
cf374c6b8b added cert password as an auto-injected resource 2017-03-23 08:29:47 -06:00
David Sparer
82388dcbc3 added finger-printing to artifacting step 2017-03-23 08:26:18 -06:00
David Sparer
7a6a99e2b6 attempting to use the publishing jenkinsfile from scm 2017-03-23 08:08:29 -06:00
David Sparer
c383736834 more debug code 2017-03-22 17:06:30 -06:00
David Sparer
6e5e78df3b investigating certificate unlock issues 2017-03-22 17:03:38 -06:00
David Sparer
311bf1b641 fix issue with retrieving fuzzy file name 2017-03-22 16:48:38 -06:00
David Sparer
5c9933791c do base64 decoding in the script 2017-03-22 16:39:47 -06:00
David Sparer
039d4d11aa add a cast to help aleviate bat file issues 2017-03-22 16:33:12 -06:00
David Sparer
c0f2d2aa84 fixed bug 2017-03-22 16:27:28 -06:00
David Sparer
45099bfa07 try to get around weird type casting issue 2017-03-22 16:22:53 -06:00
David Sparer
695ae9d970 added script for publishing a release to github 2017-03-22 14:41:35 -06:00
David Sparer
21eb0064b1 enable code signing for installer 2017-03-22 08:45:25 -06:00
David Sparer
513fe402af signed the firefox binaries 2017-03-21 12:47:47 -06:00
David Sparer
b27e5754e8 fix arg passing 2017-03-21 12:07:49 -06:00
David Sparer
fa7231d77b added puttyng.exe to the sign files exclusion list 2017-03-21 11:52:52 -06:00
David Sparer
f5a30ecb33 added some more support for excluding files from signing 2017-03-21 11:42:50 -06:00
David Sparer
7f22289889 add previously signed puttyng binary 2017-03-21 11:21:12 -06:00
David Sparer
f80c39077a Added ability to exclude items from signing 2017-03-21 11:19:09 -06:00
David Sparer
75c60a1cc4 release certificate resources after we've used them 2017-03-21 11:16:05 -06:00
David Sparer
2cf38d6b7c removed some debug code 2017-03-21 11:15:16 -06:00
David Sparer
482c9c1574 added some temp debugging code 2017-03-21 11:10:33 -06:00
David Sparer
882e59a260 normalized the unit test output folder for the portable builds 2017-03-21 10:55:18 -06:00
David Sparer
7a036956b7 added some certificate checks to be more sure that the editbin we're using is legit 2017-03-21 10:29:48 -06:00
David Sparer
7520b20cf9 fixed bug in setting largeaddressaware 2017-03-21 10:28:49 -06:00
David Sparer
d47ccd75d5 Revert "removed unnecessary build configs for the unit tests project"
This reverts commit 56ff81a0ed.
2017-03-21 10:20:20 -06:00
David Sparer
56ff81a0ed removed unnecessary build configs for the unit tests project
im not even sure we need to distinguish between debug and portable builds, but ill leave it like this for now
2017-03-21 10:10:48 -06:00
David Sparer
8db76f5324 actually fix the sensitive param leakage 2017-03-18 17:25:30 -06:00
David Sparer
a9442ea06e added some error output for cert loading action 2017-03-18 16:30:03 -06:00
David Sparer
92bd0d3ea0 do not echo sensitive params 2017-03-18 16:29:44 -06:00
David Sparer
512d7322b2 request cert path and password as script parameters 2017-03-18 16:13:20 -06:00
David Sparer
45645c439f test of msbuild param passing 2017-03-18 15:13:23 -06:00
David Sparer
84ebb82cae the installer project now uses a powershell script for post build actions 2017-03-18 00:24:39 -06:00
David Sparer
576f6a3bd6 fixed issue with tidying release files 2017-03-18 00:24:07 -06:00
David Sparer
96df821eca changed signature failures from errors to warnings 2017-03-18 00:23:44 -06:00
David Sparer
8589778e92 split postbuild actions into powershell scripts 2017-03-17 23:53:59 -06:00
David Sparer
a8a7de9ee6 began converting all post build actions to powershell 2017-03-17 18:01:08 -06:00
David Sparer
1d99340425 remove quoting 2017-03-17 16:33:27 -06:00
David Sparer
a8cdfb56f3 single quote might be safer 2017-03-17 16:18:20 -06:00
David Sparer
0958cdaa2d ensure paths are quoted 2017-03-17 16:13:12 -06:00
David Sparer
ebfb3dd31e added a build config for the installer 2017-03-17 16:01:50 -06:00
105 changed files with 1878 additions and 3322 deletions

View File

@@ -1,3 +1,99 @@
1.75.7011 (2017-xx-xx):
Fixes:
------
#761: Connections using external tools do not start (introduced in v1.75.7009)
Minor changes to how the connection tree column widths are calculated
1.75.7010 (2017-10-29):
Fixes:
------
#756: CustomConsPath always null
1.75.7009 (2017-10-28):
Fixes:
------
#676: Portable version ignores /cons param on first run
#675: Attempting to add new connection/folder does not work in some situations
#665: Can not add new connection or new folder in some situations
#658: Keep Port Scan tab open after import
#646: Exception after click on import port scan
#635: Updated PuTTYNG to 0.70
#610: mRemoteNG cannot start /crashes for some users on Windows server 2012 R2 server
#600: Missing horizontal scrollbar on Connections Panel
#596: Exception when launching external tool without a connection selected
#550: Sometimes double-clicking connection tree node began rename instead of connecting
#536: Prevented log file creation when writeLogFile option is not set
#529: Erratic Tree Selection when using SQL Database
#482: Default connection password not decrypted when loaded
#335: The Quick Connect Toolbar > Connection view does not show open connections with the play icon
#176: Unable to enter text in Quick Connect when SSH connection active
Minor error message correction
Minor code refactoring
NO.RELEASE (2017-06-15):
Fixed in previous releases:
---------------------------
#466: Installer still failing on Win7 for updates - v1.75.7005 (Hotifx 5)
#462: Remove no longer used files from portable version - v1.75.7003 (Hotfix 4)
1.75.7008 (2017-06-15):
Fixes:
------
#589: MSI doesn't update with newer PuTTYNG version that fixes #583 (Again, Sorry!)
Minor updates to the installer build
1.75.7007 (2017-06-14):
Fixes:
------
#583: SSH (PuTTYNG) Sessions are not properly integrated into the main mRemoteNG window (Sorry!)
1.75.7006 (2017-06-13):
Fixes:
------
#377: Use all space on About page
#527: Additional protections to avoid problems on update check in heavily firewalled environments
#530: Fixed issue where using External Tool on existing connection causes creation of 'New Connection' entry
#531: Update PuTTYNG to 0.69
#546: Quick Connect from notification area icon displays warning when clicking on a folder (see #334)
1.75.7005 (2017-04-27):
Fixes:
------
#410: Update PuTTYNG to 0.68
#434: Fix complier warnings CA1049 & CA2111
#442: Fixed issue loading PuTTY sessions that have spaces in the name
#502: Problems with ParentID for Duplicated Containers/Connections with SQL Connection Storage
#514: Expanded property not saved/loaded properly from SQL
#518: Exception when Importing File
General Changes:
----------------
Minor code cleanup/optimizations/null checks
1.75.7003 (2017-03-24):
Fixes:
------
#464: Resolved issue when importing a connections file while using SQL server feature
1.75.7002 (2017-03-10):
Fixes:

View File

@@ -11,7 +11,9 @@ Bennett Blodinger (github.com/benwa)
Joe Cefoli (github.com/jcefoli)
countchappy (github.com/countchappy)
Tony Lambert
Brandon Wulf (github.com/mrwulf)
Pedro Rodrigues (github.com/pedro2555)
github.com/dekelMP
Past Contributors
@@ -99,8 +101,8 @@ Copyright
Freely redistributable with attribution
http://www.dotnetmagic.com/magic_download.html
PuTTY 0.67
Copyright <20> 1997-2016 Simon Tatham
PuTTY 0.68
Copyright <20> 1997-2017 Simon Tatham
MIT License
http://www.chiark.greenend.org.uk/~sgtatham/putty/

View File

@@ -17,7 +17,7 @@
<?define RequiredDotNetFrameworkServicePackLevel = "" ?>
<?define RequiredDotNetFrameworkVersion = "$(var.RequiredDotNetFrameworkMajorVersion).$(var.RequiredDotNetFrameworkMinorVersion)" ?>
<?define Rdp80Kb = "KB2592687" ?>
<?define Rdp81Kb = "KB2923545" ?>
<?define Rdp81Kb = "KB2830477" ?>
<?define MinimumRdpKb = $(var.Rdp80Kb) ?>
<?define RdpDtlsKb = "KB2574819" ?>
<?define IGNOREPREREQUISITES = 0 ?>

View File

@@ -39,9 +39,6 @@
<Compile Include="mRemoteNGV1.wxs" />
</ItemGroup>
<ItemGroup>
<Content Include="Dependencies\PuTTYNG.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Filters\Harvest_Filter.xslt" />
<Content Include="Includes\Config.wxi" />
<Content Include="Resources\header.bmp" />
@@ -57,7 +54,6 @@
<Folder Include="Localizations" />
<Folder Include="Filters" />
<Folder Include="bin" />
<Folder Include="Dependencies" />
<Folder Include="Resources" />
</ItemGroup>
<ItemGroup>
@@ -115,20 +111,19 @@
<DefineConstants>HarvestPath=$(SolutionDir)mRemoteV1\bin\Release Portable;HelpFilesHarvestPath=$(SolutionDir)mRemoteV1\Resources\Help</DefineConstants>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>set /p buildenv=&lt;buildenv.tmp
<PostBuildEvent>:: When passing paths to powershell scripts, check if the path ends with a backslash "\"
:: If it does, then the backslash may be interpreted as an escape character. Add another backslash to cancel the first one.
REM Sign MSI
IF EXIST C:\mRemoteNG_code_signing_cert.pfx (
IF %25buildenv: Portable=%25==Release (
powershell "&amp;""$(SolutionDir)Tools\signfiles.ps1""" %27%25cd%25%27
)
)
powershell -noprofile -command "sleep 2"
set /p buildenv=&lt;buildenv.tmp
set solutionDir=$(SolutionDir)\
set targetDir=%25cd%25
set psScriptsDir=$(SolutionDir)Tools
set certPath=$(CertPath)
set certPassword=$(CertPassword)
REM Rename MSI to include version number
powershell -ExecutionPolicy Bypass -File "$(SolutionDir)Tools\rename_installer_with_version.ps1" $(SolutionDir)
REM Copy MSI to Release folder
IF %25buildenv: Portable=%25==Release (powershell -ExecutionPolicy Bypass -File "$(SolutionDir)Tools\copy_release_installer.ps1" $(TargetDir) $(SolutionDir)Release)</PostBuildEvent>
:: Call the post build powershell script
powershell.exe -ExecutionPolicy Bypass -File "%25psScriptsDir%25\postbuild_installer.ps1" -SolutionDir "%25solutionDir%25" -TargetDir "%25targetDir%25" -TargetFileName "mRemoteNG.exe" -ConfigurationName "%25buildenv%25" -CertificatePath "%25certPath%25" -CertificatePassword "%25certPassword%25"</PostBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PreBuildEvent>REM Clean the TargetDir
@@ -137,9 +132,9 @@ rmdir /S /Q "$(TargetDir)"
echo $(ConfigurationName) &gt; buildenv.tmp
REM Harvest bin directory of the mRemoteV1 project
call "$(WIX)bin\heat.exe" dir "$(SolutionDir)mRemoteV1\bin\$(Configuration)" -ag -dr INSTALLDIR -var var.HarvestPath -srd -cg MandatoryComponents -template fragment -out "$(ProjectDir)Fragments\FilesFragment.wxs" -t "$(ProjectDir)Filters\Harvest_Filter.xslt" -v
"$(WIX)bin\heat.exe" dir "$(SolutionDir)mRemoteV1\bin\$(Configuration)" -ag -nologo -dr INSTALLDIR -var var.HarvestPath -srd -cg MandatoryComponents -template fragment -out "$(ProjectDir)Fragments\FilesFragment.wxs" -t "$(ProjectDir)Filters\Harvest_Filter.xslt"
REM Convert the license file "COPYING.TXT" to "License.rtf" to be shown in the installer GUI
call "$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
"$(ProjectDir)Resources\Pandoc\pandoc.exe" -s -t rtf -o "$(ProjectDir)\Resources\License.rtf" "$(SolutionDir)COPYING.TXT"</PreBuildEvent>
</PropertyGroup>
</Project>

View File

@@ -6,7 +6,7 @@
<String Id="Install_NeedToBeAdminToInstall">You need to be an administrator to install this product.</String>
<String Id="Install_NeedDotNetFrameworkVersion">mRemoteNG requires Microsoft .NET Framework [REQUIREDDOTNETFRAMEWORKVERSION] or higher.</String>
<String Id="Install_OSVersionRequirement">mRemoteNG requires Windows 7 SP1 or higher to run. Please update your operating system and try again.</String>
<String Id="Install_RDP80Requirement">mRemoteNG requires RDP 8.0 or higher to run. Windows 7 users will need to install KB2592687</String>
<String Id="Install_RDP80Requirement">mRemoteNG requires RDP 8.0 or higher to run. Windows 7 users will need to install either KB2592687 (RDP 8.0) or KB2830477 (RDP 8.1)</String>
<String Id="Install_RDPDtlsRequirement">mRemoteNG requires KB2574819 in order to create RDP connections. Windows 7 users will need to install this KB.</String>
<String Id="Install_Win7RequiresSP1">For mRemoteNG to run on Windows 7, it requires Service Pack 1 to be installed. Please install Service Pack 1 and try again.</String>

View File

@@ -10,6 +10,7 @@
<MajorUpgrade DowngradeErrorMessage="!(loc.Upgrade_NewerVersionInstalled)" Schedule="afterInstallExecute" />
<MediaTemplate EmbedCab="yes" />
<Binary Id="CustomActions.CA.dll" SourceFile="$(var.SolutionDir)InstallerProjects\CustomActions\bin\$(var.Configuration)\CustomActions.CA.dll" />
<Property Id="MsiLogging" Value="v" />
<Property Id="ARPPRODUCTICON" Value="mRemoteNG.ico" />
<Property Id="ARPHELPLINK" Value="http://www.mremoteng.org" />
<SetProperty Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]" After="CostFinalize" />
@@ -67,7 +68,7 @@
<Condition Message="!(loc.Install_RDPDtlsRequirement)">
<![CDATA[Installed OR (IGNOREPREREQUISITES = 1) OR (VersionNT >= 602 OR VersionNT64 >= 602) OR ((VersionNT = 601 OR VersionNT64 = 601) AND (RDP_DTLS_UPDATE_INSTALLED = 1))]]>
</Condition>
<!-- If Win7, require RDP 8.0 update (KB2592687) -->
<!-- If Win7, require RDP 8.0 (KB2592687) or 8.1 (KB2830477) update -->
<Condition Message="!(loc.Install_RDP80Requirement)">
<![CDATA[Installed OR (IGNOREPREREQUISITES = 1) OR (VersionNT >= 602 OR VersionNT64 >= 602) OR ((VersionNT = 601 OR VersionNT64 = 601) AND (MINIMUM_RDP_VERSION_INSTALLED = 1))]]>
</Condition>

View File

@@ -0,0 +1,68 @@
node('windows') {
def jobDir = pwd()
def solutionFilePath = "\"${jobDir}\\mRemoteV1.sln\""
def vsToolsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools"
def vsExtensionsDir = "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\IDE\\CommonExtensions\\Microsoft\\TestWindow"
def nunitTestAdapterPath = "C:\\Users\\Administrator\\AppData\\Local\\Microsoft\\VisualStudio\\14.0\\Extensions"
stage ('Clean output dir') {
bat script: "rmdir /S /Q \"${jobDir}\\Release\" 2>nul", returnStatus: true
}
stage ('Checkout Branch') {
checkout([
$class: 'GitSCM',
branches: [[name: '*/${TargetBranch}']],
doGenerateSubmoduleConfigurations: false,
extensions: [],
submoduleCfg: [],
userRemoteConfigs: [[
credentialsId: '9c3fbff4-5b90-402f-a298-00e607fcec87',
url: 'https://github.com/mRemoteNG/mRemoteNG.git'
]]
])
}
stage ('Restore NuGet Packages') {
def nugetPath = "C:\\nuget.exe"
bat "${nugetPath} restore ${solutionFilePath}"
}
withCredentials([file(credentialsId: '9b674d57-6792-48e3-984a-4d1bab2abb64', variable: 'CODE_SIGNING_CERT')]) {
withCredentials([usernamePassword(credentialsId: '05b7449b-05c0-490f-8661-236242526e62', passwordVariable: 'MRNG_CERT_PASSWORD', usernameVariable: 'NO_USERNAME')]) {
stage ('Build mRemoteNG (Normal - MSI)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Installer\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
archiveArtifacts artifacts: "Release\\*.msi", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
}
stage ('Build mRemoteNG (Portable)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && msbuild.exe /nologo /t:Clean,Build /p:Configuration=\"Release Portable\" /p:Platform=x86 /p:CertPath=\"${env.CODE_SIGNING_CERT}\" /p:CertPassword=${env.MRNG_CERT_PASSWORD} \"${jobDir}\\mRemoteV1.sln\""
archiveArtifacts artifacts: "Release\\*.zip", caseSensitive: false, onlyIfSuccessful: true, fingerprint: true
}
}
}
stage ('Run Unit Tests (Normal - MSI)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release\\mRemoteNGTests.dll\""
}
stage ('Run Unit Tests (Portable)') {
bat "\"${vsToolsDir}\\VsDevCmd.bat\" && VSTest.Console.exe /logger:trx /TestAdapterPath:${nunitTestAdapterPath} \"${jobDir}\\mRemoteNGTests\\bin\\Release Portable\\mRemoteNGTests.dll\""
}
stage ('Generate UpdateCheck Files') {
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\create_upg_chk_files.ps1\" -TagName \"${env.TagName}\" -UpdateChannel \"${env.UpdateChannel}\""
archiveArtifacts artifacts: "Release\\*.txt", caseSensitive: false, onlyIfSuccessful: true
}
stage ('Publish to GitHub') {
withCredentials([string(credentialsId: '5443a369-dbe8-42d3-b4e8-04d0b4e9039a', variable: 'GH_AUTH_TOKEN')]) {
def zipPath = "${jobDir}\\Release\\*.zip"
def msiPath = "${jobDir}\\Release\\*.msi"
// because batch files suck at handling newline characters, we have to convert to base64 in groovy and back to text in powershell
def base64Description = env.ReleaseDescription.bytes.encodeBase64().toString()
bat "powershell -ExecutionPolicy Bypass -File \"${jobDir}\\Tools\\publish_to_github.ps1\" -Owner \"mRemoteNG\" -Repository \"mRemoteNG\" -ReleaseTitle \"${env.ReleaseTitle}\" -TagName \"${env.TagName}\" -TargetCommitish \"${env.TargetBranch}\" -Description \"${base64Description}\" -IsDraft ${env.IsDraft} -IsPrerelease ${env.IsPreRelease} -ZipFilePath \"${zipPath}\" -MsiFilePath \"${msiPath}\" -AuthToken \"${env.GH_AUTH_TOKEN}\" -DescriptionIsBase64Encoded"
}
}
}

View File

@@ -10,8 +10,8 @@
| Update Channel | Build Status | Downloads |
| ---------------|--------------|-----------|
| Stable | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/master)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.74/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.74) |
| Beta | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/beta_channel)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/beta_channel/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Beta3/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Beta3) |
| Stable | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/master)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/master/) | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Hotfix7/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Hotfix7) |
| Beta | | [![Github Releases (by Release)](https://img.shields.io/github/downloads/mRemoteNG/mRemoteNG/v1.75Hotfix7/total.svg)](https://github.com/mRemoteNG/mRemoteNG/releases/tag/v1.75Hotfix7) |
| Development | [![Build Status](https://jenkins.mremoteng.org/buildStatus/icon?job=mRemoteNG/mRemoteNG/develop)](https://jenkins.mremoteng.org/job/mRemoteNG/job/mRemoteNG/job/develop/) | - |
@@ -26,9 +26,9 @@ Currently these protocols are supported:
* VNC (Virtual Network Computing)
* ICA (Independent Computing Architecture)
* SSH (Secure Shell)
* Telnet (TELecommunication NETwork)
* HTTP/S (Hypertext Transfer Protocol)
* Rlogin (Rlogin)
* Telnet (Teletype Network)
* HTTP/S (Hypertext Transfer Protocol Secure)
* Rlogin (Remote Login)
* RAW
mRemoteNG can be installed on Windows 7 or later.

15
Tools/copy_puttyng.ps1 Normal file
View File

@@ -0,0 +1,15 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
Write-Output "Copying PUTTYNG to correct directory"
Copy-Item -Path (Join-Path -Path $SolutionDir -ChildPath "mRemoteV1\Resources\PuTTYNG.exe") -Destination $TargetDir -Force
Write-Output ""

View File

@@ -1,16 +1,21 @@
$sourcePath = $args[0]
$destinationDir = $args[1]
param (
[string]
$SourcePath,
Write-Host $sourcePath
Write-Host $destinationDir
[string]
$DestinationDir
)
if (!(Test-Path -Path $destinationDir))
Write-Host $SourcePath
Write-Host $DestinationDir
if (!(Test-Path -Path $DestinationDir))
{
New-Item -Path $destinationDir -ItemType "directory"
New-Item -Path $DestinationDir -ItemType "directory"
}
$sourceFiles = Get-ChildItem -Path $sourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
$sourceFiles = Get-ChildItem -Path $SourcePath -Recurse | ?{$_.Extension -match "exe|msi"}
foreach ($item in $sourceFiles)
{
Copy-Item -Path $item.FullName -Destination $destinationDir -Force
Copy-Item -Path $item.FullName -Destination $DestinationDir -Force
}

View File

@@ -1,42 +1,109 @@
#Requires -Version 4.0
param (
[string]
[Parameter(Mandatory=$true)]
$TagName,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Stable","Beta","Development")]
$UpdateChannel
)
function New-MsiUpdateFileContent {
param (
[System.IO.FileInfo]
[Parameter(Mandatory=$true)]
$MsiFile,
[string]
[Parameter(Mandatory=$true)]
$TagName
)
$version = $MsiFile.BaseName -replace "[a-zA-Z-]*"
$certThumbprint = (Get-AuthenticodeSignature -FilePath $MsiFile).SignerCertificate.Thumbprint
$hash = Get-FileHash -Algorithm SHA512 $MsiFile | % { $_.Hash }
$fileContents = `
"Version: $version
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$TagName/$($MsiFile.Name)
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$TagName/CHANGELOG.TXT
CertificateThumbprint: $certThumbprint
Checksum: $hash"
Write-Output $fileContents
}
function New-ZipUpdateFileContent {
param (
[System.IO.FileInfo]
[Parameter(Mandatory=$true)]
$ZipFile,
[string]
[Parameter(Mandatory=$true)]
$TagName
)
$version = $ZipFile.BaseName -replace "[a-zA-Z-]*"
$hash = Get-FileHash -Algorithm SHA512 $ZipFile | % { $_.Hash }
$fileContents = `
"Version: $version
dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$TagName/$($ZipFile.Name)
clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$TagName/CHANGELOG.TXT
Checksum: $hash"
Write-Output $fileContents
}
function Resolve-UpdateCheckFileName {
param (
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Stable","Beta","Development")]
$UpdateChannel,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("Normal","Portable")]
$Type
)
$fileName = ""
if ($UpdateChannel -eq "Beta") { $fileName += "beta-" }
elseif ($UpdateChannel -eq "Development") { $fileName += "dev-" }
$fileName += "update"
if ($Type -eq "Portable") { $fileName += "-portable" }
$fileName += ".txt"
Write-Output $fileName
}
$releaseFolder = Join-Path -Path $PSScriptRoot -ChildPath "..\Release" -Resolve
$tag = Read-Host -Prompt 'Tag name'
Write-Host
Write-Host
Write-Host
# build msi update file
$msiFile = Get-ChildItem -Path "$releaseFolder\*.msi" | sort LastWriteTime | select -last 1
$msiUpdateContents = New-MsiUpdateFileContent -MsiFile $msiFile -TagName $TagName
$msiUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Normal
Write-Output "`n`nMSI Update Check File Contents ($msiUpdateFileName)`n------------------------------"
Tee-Object -InputObject $msiUpdateContents -FilePath "$releaseFolder\$msiUpdateFileName"
Write-Host PORTABLE
Write-Host --------
$file = Get-ChildItem -Path "$releaseFolder\*.zip" | sort LastWriteTime | select -last 1 | % { $_.FullName }
$filename = $file.Split("\") | select -last 1
$version = $file.tostring().Split("-")[2].trim(".zip")
Write-Host Version: $version
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
$hash = Get-FileHash -Algorithm SHA512 $file | % { $_.Hash }
Write-Host Checksum: $hash
Write-Host
Write-Host
Write-Host
Write-Host MSI
Write-Host ---
$file = Get-ChildItem -Path "$releaseFolder\*.msi" | sort LastWriteTime | select -last 1 | % { $_.FullName }
$filename = $file.Split("\") | select -last 1
$version = $file.tostring().Split("-")[2].trim(".msi")
Write-Host Version: $version
Write-Host dURL: https://github.com/mRemoteNG/mRemoteNG/releases/download/$tag/$filename
Write-Host clURL: https://raw.githubusercontent.com/mRemoteNG/mRemoteNG/$tag/CHANGELOG.TXT
Write-Host CertificateThumbprint: 0CEA828E5C787EA8AA89268D83816C1EA03375BA
$hash = Get-FileHash -Algorithm SHA512 $file | % { $_.Hash }
Write-Host Checksum: $hash
# build zip update file
$zipFile = Get-ChildItem -Path "$releaseFolder\*.zip" | sort LastWriteTime | select -last 1
$zipUpdateContents = New-ZipUpdateFileContent -ZipFile $zipFile -TagName $TagName
$zipUpdateFileName = Resolve-UpdateCheckFileName -UpdateChannel $UpdateChannel -Type Portable
Write-Output "`n`nZip Update Check File Contents ($zipUpdateFileName)`n------------------------------"
Tee-Object -InputObject $zipUpdateContents -FilePath "$releaseFolder\$zipUpdateFileName"

220
Tools/github_functions.ps1 Normal file
View File

@@ -0,0 +1,220 @@
$githubUrl = 'https://api.github.com'
function Publish-GitHubRelease {
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseTitle,
[string]
[Parameter(Mandatory=$true)]
#
$TagName,
[string]
[Parameter(Mandatory=$true)]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
[Parameter(Mandatory=$true)]
#
$Description,
[bool]
[Parameter(Mandatory=$true)]
#
$IsDraft,
[bool]
[Parameter(Mandatory=$true)]
#
$IsPrerelease,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$body = New-GitHubReleaseRequestBody -TagName $TagName -TargetCommitish $TargetCommitish -ReleaseTitle $ReleaseTitle -Description $Description -IsDraft $IsDraft -IsPrerelease $IsPrerelease
$req_publishRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body $body -ErrorAction Stop
$response_publishRelease = ConvertFrom-Json -InputObject $req_publishRelease.Content
Write-Output $response_publishRelease
}
function Edit-GitHubRelease {
param (
[string]
#[Parameter(Mandatory=$true)]
#
$Owner,
[string]
#[Parameter(Mandatory=$true)]
#
$Repository,
[string]
#[Parameter(Mandatory=$true)]
#
$ReleaseId,
[string]
#
$ReleaseTitle,
[string]
#
$TagName,
[string]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
#
$Description,
[bool]
#
$IsDraft,
[bool]
#
$IsPrerelease,
[string]
#[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$body_params = @{
"TagName" = $TagName
"TargetCommitish" = $TargetCommitish
"ReleaseTitle" = $ReleaseTitle
"Description" = $Description
}
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("IsDraft", $IsDraft) }
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("IsPrerelease", $IsPrerelease) }
$body = New-GitHubReleaseRequestBody @body_params
$req_editRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases/$ReleaseId" -Method Post -Headers @{"Authorization"="token $AuthToken"} -Body $body -ErrorAction Stop
$response_editRelease = ConvertFrom-Json -InputObject $req_editRelease.Content
Write-Output $response_editRelease
}
function Get-GitHubRelease {
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseId,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$req_getRelease = Invoke-WebRequest -Uri "$githubUrl/repos/$Owner/$Repository/releases/$ReleaseId" -Method Get -Headers @{"Authorization"="token $AuthToken"} -ErrorAction Stop
$response_getRelease = ConvertFrom-Json -InputObject $req_getRelease.Content
Write-Output $response_getRelease
}
function Upload-GitHubReleaseAsset {
param (
[string]
[Parameter(Mandatory=$true)]
$UploadUri,
[string]
[Parameter(Mandatory=$true)]
# Path to the file to upload with the release
$FilePath,
[string]
[Parameter(Mandatory=$true)]
# Content type of the file
$ContentType,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
$UploadUri = $UploadUri -replace "(\{[\w,\?]*\})$"
$file = Get-Item -Path $FilePath
$req_uploadZipAsset = Invoke-WebRequest -Uri "$($UploadUri)?name=$($file.Name)" -Method Post -Headers @{"Authorization"="token $AuthToken"} -ContentType $ContentType -InFile $file.FullName -ErrorAction Stop
}
function New-GitHubReleaseRequestBody {
param (
[string]
#
$TagName,
[string]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
# Title of the release
$ReleaseTitle,
[string]
# Description of the release
$Description,
[bool]
# Is this a draft?
$IsDraft,
[bool]
# Is this a pre-release?
$IsPrerelease
)
$body_params = [ordered]@{}
if ($TagName -ne "") { $body_params.Add("tag_name", $TagName) }
if ($TargetCommitish -ne "") { $body_params.Add("target_commitish", $TargetCommitish) }
if ($ReleaseTitle -ne "") { $body_params.Add("name", $ReleaseTitle) }
if ($Description -ne "") { $body_params.Add("body", $Description) }
if ($PSBoundParameters.ContainsKey("IsDraft")) { $body_params.Add("draft", $IsDraft) }
if ($PSBoundParameters.ContainsKey("IsPrerelease")) { $body_params.Add("prerelease", $IsPrerelease) }
$json_body = ConvertTo-Json -InputObject $body_params -Compress
Write-Output $json_body
}

23
Tools/move_help_files.ps1 Normal file
View File

@@ -0,0 +1,23 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
$path_HelpFilesDir = Join-Path -Path $TargetDir -ChildPath "Help"
Write-Output "Moving Help files to correct directory"
# Remove stale Help files, if they exist
if (Test-Path -Path $path_HelpFilesDir) {
Remove-Item -Path $path_HelpFilesDir -Recurse -Force
}
# Move Help files
Move-Item -Path (Join-Path -Path $TargetDir -ChildPath "Resources\Help") -Destination $path_HelpFilesDir -Force
Start-Sleep -Seconds 2
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "Resources") -Recurse -Force
Write-Output ""

View File

@@ -0,0 +1,43 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
$CertificatePath,
[string]
$CertificatePassword,
[string[]]
$ExcludeFromSigning
)
Write-Output "+=================================================================+"
Write-Output "| Beginning mRemoteNG Installer Post Build |"
Write-Output "+=================================================================+"
Format-Table -AutoSize -Wrap -InputObject @{
"SolutionDir" = $SolutionDir
"TargetDir" = $TargetDir
"TargetFileName" = $TargetFileName
"ConfigurationName" = $ConfigurationName
"ExcludeFromSigning" = $ExcludeFromSigning
}
& "$PSScriptRoot\sign_binaries.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName -CertificatePath $CertificatePath
& "$PSScriptRoot\rename_installer_with_version.ps1" -SolutionDir $SolutionDir
& "$PSScriptRoot\copy_release_installer.ps1" -SourcePath $TargetDir -DestinationDir (Join-Path -Path $SolutionDir -ChildPath "Release")

View File

@@ -0,0 +1,47 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
$CertificatePath,
[string]
$CertificatePassword,
[string[]]
$ExcludeFromSigning
)
Write-Output "+=================================================================+"
Write-Output "| Beginning mRemoteV1 Post Build |"
Write-Output "+=================================================================+"
Format-Table -AutoSize -Wrap -InputObject @{
"SolutionDir" = $SolutionDir
"TargetDir" = $TargetDir
"TargetFileName" = $TargetFileName
"ConfigurationName" = $ConfigurationName
"ExcludeFromSigning" = $ExcludeFromSigning
}
& "$PSScriptRoot\copy_puttyng.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir
& "$PSScriptRoot\move_help_files.ps1" -TargetDir $TargetDir
& "$PSScriptRoot\set_LargeAddressAware.ps1" -TargetDir $TargetDir -TargetFileName $TargetFileName
& "$PSScriptRoot\tidy_files_for_release.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\sign_binaries.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -CertificatePath $CertificatePath -CertificatePassword $CertificatePassword -ConfigurationName $ConfigurationName -Exclude $ExcludeFromSigning
& "$PSScriptRoot\verify_binary_signatures.ps1" -TargetDir $TargetDir -ConfigurationName $ConfigurationName
& "$PSScriptRoot\zip_portable_files.ps1" -SolutionDir $SolutionDir -TargetDir $TargetDir -ConfigurationName $ConfigurationName

View File

@@ -0,0 +1,25 @@
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseId,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken
)
. "$PSScriptRoot\github_functions.ps1"
Edit-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $ReleaseId -AuthToken $AuthToken -IsDraft $false

View File

@@ -0,0 +1,76 @@
param (
[string]
[Parameter(Mandatory=$true)]
#
$Owner,
[string]
[Parameter(Mandatory=$true)]
#
$Repository,
[string]
[Parameter(Mandatory=$true)]
#
$ReleaseTitle,
[string]
[Parameter(Mandatory=$true)]
#
$TagName,
[string]
[Parameter(Mandatory=$true)]
# Either the SHA of the commit to target or the branch name.
$TargetCommitish,
[string]
[Parameter(Mandatory=$true)]
#
$Description,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("true","false")]
# true/false
$IsDraft,
[string]
[Parameter(Mandatory=$true)]
[ValidateSet("true","false")]
# true/false
$IsPrerelease,
[string]
[Parameter(Mandatory=$true)]
# Path to the zip file to upload with the release
$ZipFilePath,
[string]
[Parameter(Mandatory=$true)]
#Path to the msi file to upload with the release
$MsiFilePath,
[string]
[Parameter(Mandatory=$true)]
# The OAuth2 token to use for authentication.
$AuthToken,
[switch]
# Enable this switch to treat $Description as a Base64 encoded string. It will be decoded before being used elsewhere in the script.
$DescriptionIsBase64Encoded
)
if ($DescriptionIsBase64Encoded) {
$Description = ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Description)))
}
. "$PSScriptRoot\github_functions.ps1"
$release = Publish-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseTitle $ReleaseTitle -TagName $TagName -TargetCommitish $TargetCommitish -Description $Description -IsDraft ([bool]::Parse($IsDraft)) -IsPrerelease ([bool]::Parse($IsPrerelease)) -AuthToken $AuthToken
$zipUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $ZipFilePath -ContentType "application/zip" -AuthToken $AuthToken
$msiUpload = Upload-GitHubReleaseAsset -UploadUri $release.upload_url -FilePath $MsiFilePath -ContentType "application/octet-stream" -AuthToken $AuthToken
Write-Output (Get-GitHubRelease -Owner $Owner -Repository $Repository -ReleaseId $release.id -AuthToken $AuthToken)

View File

@@ -1,11 +1,15 @@
$solutionDir = $args[0]
$renameTarget = $solutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
param (
[string]
$SolutionDir
)
Write-Host $solutionDir
$renameTarget = $SolutionDir + "InstallerProjects\Installer\bin\Release\en-US\mRemoteNG-Installer.msi"
Write-Host $SolutionDir
Write-Host $renameTarget
$targetVersionedFile = "$solutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
$version = &"$solutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
$targetVersionedFile = "$SolutionDir\mRemoteV1\bin\Release\mRemoteNG.exe"
$version = &"$SolutionDir\Tools\sigcheck.exe" /accepteula -q -n $targetVersionedFile
$renameTargetFileObject = Get-Item -Path $renameTarget -ErrorAction SilentlyContinue

View File

@@ -0,0 +1,43 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$TargetFileName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
# Find editbin.exe
#Resolve-Path tends to be faster, but since editbin's are all over the place it's not 100% effective
$editBinPath = @((Resolve-Path -Path "C:\Program Files*\Microsoft Visual Studio*\VC\bin\editbin.exe").Path)
if(!$editBinPath)
{
# This should work on all VS versions, but doesn't on our Jenkin's build for some reason...
# This is needed VC Community
$editBinPath = @((gci -Path "C:\Program*\Microsoft Visual Studio\" -Filter editbin.exe -Recurse)[0].FullName)
}
# if we STILL can't find it, just return. Same end result NUnit test will fail.
if(!$editBinPath)
{
echo "Could not find editbin.exe - Can't set LargeAddressAware"
return
}
echo "editBinPath value:"
echo $editBinPath
# Verify editbin certificate
& "$PSScriptRoot\validate_microsoft_tool.ps1" -FullPath "$editBinPath"
$outputExe = Join-Path -Path $TargetDir -ChildPath $TargetFileName
# Set LargeAddressAware
Write-Output "Setting LargeAddressAware on binary file `"$outputExe`""
& $editBinPath "/largeaddressaware" "$outputExe"
Write-Output ""

80
Tools/sign_binaries.ps1 Normal file
View File

@@ -0,0 +1,80 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string[]]
# File names to exclude from signing
$Exclude,
[string]
# The code signing certificate to use when signing the files.
$CertificatePath,
[string]
# Password to unlock the code signing certificate.
$CertificatePassword
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
if ($ConfigurationName -notmatch "Release") {
Write-Output "This is not a release build - we won't sign files."
return
}
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf)) {
Write-Output "Certificate is not present - we won't sign files."
return
}
if ($CertificatePassword -eq "") {
Write-Output "No certificate password was provided - we won't sign files."
return
}
try {
$certKeyStore = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertificatePath, $CertificatePassword, $certKeyStore) -ErrorAction Stop
} catch {
Write-Output "Error loading certificate file - we won't sign files."
Write-Output $Error[0]
return
}
# Sign MSI if we are building a release version and the certificate is available
Write-Output "Signing Binaries"
Write-Output "Getting files from path: $TargetDir"
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -notcontains $_.Name}
$excluded_files = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"} | ?{$Exclude -contains $_.Name}
$excluded_files | ForEach-Object `
-Begin { Write-Output "The following files were excluded from signing due to being on the exclusion list:" } `
-Process { Write-Output "-- $($_.FullName)" }
Write-Output "Signable files count: $($signableFiles.Count)"
foreach ($file in $signableFiles) {
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
}
# Release certificate
if ($cert -ne $null) {
$cert.Dispose()
}
Write-Output ""

View File

@@ -1,13 +0,0 @@
$timeserver = "http://timestamp.verisign.com/scripts/timstamp.dll"
$certPath = "C:\mRemoteNG_code_signing_cert.pfx"
$certPassword = (Get-Credential -Message "Enter the password for the certificate" -UserName "USERNAME NOT NEEDED").Password
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath, $certPassword)
$targetPath = $args[0]
Write-Output "Getting files from path: $targetPath"
$signableFiles = Get-ChildItem -Path $targetPath -Recurse | ?{$_.Extension -match "dll|exe|msi"}
Write-Output "Signable files count: $($signableFiles.Count)"
foreach ($file in $signableFiles) {
Set-AuthenticodeSignature -Certificate $cert -TimestampServer $timeserver -IncludeChain all -FilePath $file.FullName
}

View File

@@ -0,0 +1,33 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
# Remove unnecessary files from Release versions
if ($ConfigurationName -match "Release") {
Write-Output "Removing unnecessary files from Release versions"
Remove-Item -Path (Join-Path -Path $TargetDir -ChildPath "app.publish") -Recurse -Force
$filesToDelete = Get-ChildItem -Path $TargetDir -Recurse -Include @(
"*.pdb",
"*.publish",
"*.xml",
"*.backup",
"*.log",
"*vshost*",
"*.tmp"
)
Remove-Item -Path $filesToDelete.FullName
Write-Output $filesToDelete.FullName
}
else {
Write-Output "We will not remove anything - this is not a release build."
}
Write-Output ""

View File

@@ -0,0 +1,17 @@
# $FullPath Full path to the Microsoft executable to validate
param (
[string]
[Parameter(Mandatory=$true)]
$FullPath
)
$validMSCertThumbprints = @("3BDA323E552DB1FDE5F4FBEE75D6D5B2B187EEDC", "108E2BA23632620C427C570B6D9DB51AC31387FE", "98ED99A67886D020C564923B7DF25E9AC019DF26", "5EAD300DC7E4D637948ECB0ED829A072BD152E17")
$exeSignature = Get-AuthenticodeSignature -FilePath $FullPath
$baseErrorMsg = "Could not validate the certificate of $FullPath. "
if ($exeSignature.Status -ne "Valid") {
Write-Error -Message ($baseErrorMsg+"The signature was invalid.") -ErrorAction Stop
}
elseif ($validMSCertThumbprints -notcontains $exeSignature.SignerCertificate.Thumbprint) {
Write-Error -Message ($baseErrorMsg+"The certificate thumbprint ($($exeSignature.SignerCertificate.Thumbprint)) is not trusted.") -ErrorAction Stop
}

View File

@@ -0,0 +1,47 @@
param (
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName,
[string]
# The code signing certificate to use when signing the files.
$CertificatePath
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
# validate release versions and if the certificate is available
if ($ConfigurationName -match "Release") {
if ($CertificatePath -eq "" -or !(Test-Path -Path $CertificatePath -PathType Leaf))
{
Write-Output "Certificate is not present - files likely not signed - we won't verify file signatures."
return
}
Write-Output "Verifying signature of binaries"
Write-Output "Getting files from path: $TargetDir"
$signableFiles = Get-ChildItem -Path $TargetDir -Recurse | ?{$_.Extension -match "dll|exe|msi"}
Write-Output "Signable files count: $($signableFiles.Count)"
$badSignatureFound = $false
foreach ($file in $signableFiles) {
$signature = Get-AuthenticodeSignature -FilePath $file.FullName
if ($signature.Status -ne "Valid") {
Write-Warning "File $($file.FullName) does not have a valid signature."
$badSignatureFound = $true
}
}
if ($badSignatureFound) {
Write-Output "One or more files were improperly signed."
} else {
Write-Output "All files have valid signatures."
}
} else {
Write-Output "This is not a release build - we won't verify file signatures."
}
Write-Output ""

View File

@@ -0,0 +1,28 @@
param (
[string]
[Parameter(Mandatory=$true)]
$SolutionDir,
[string]
[Parameter(Mandatory=$true)]
$TargetDir,
[string]
[Parameter(Mandatory=$true)]
$ConfigurationName
)
Write-Output "===== Beginning $($PSCmdlet.MyInvocation.MyCommand) ====="
$path_packageZipScript = Join-Path -Path $SolutionDir -ChildPath "Tools\build-relport.cmd"
# Package Zip
if ($ConfigurationName -match "Release" -and $ConfigurationName -match "Portable") {
Write-Output "Packaging Release Portable ZIP"
& $path_packageZipScript
}
else {
Write-Output "We will not zip anything - this isnt a portable release build."
}
Write-Output ""

View File

@@ -0,0 +1,55 @@
using System.Data;
using System.Linq;
using mRemoteNG.Config.Serializers;
using mRemoteNG.Connection;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNGTests.TestHelpers;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
{
public class DataTableDeserializerTests
{
private DataTableDeserializer _deserializer;
[SetUp]
public void Setup()
{
}
[Test]
public void WeCanDeserializeATree()
{
var model = CreateConnectionTreeModel();
var dataTable = CreateDataTable(model.RootNodes[0]);
_deserializer = new DataTableDeserializer(dataTable);
var output = _deserializer.Deserialize();
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(model.GetRecursiveChildList().Count()));
}
[Test]
public void WeCanDeserializeASingleEntry()
{
var dataTable = CreateDataTable(new ConnectionInfo());
_deserializer = new DataTableDeserializer(dataTable);
var output = _deserializer.Deserialize();
Assert.That(output.GetRecursiveChildList().Count(), Is.EqualTo(1));
}
private DataTable CreateDataTable(ConnectionInfo tableContent)
{
var serializer = new DataTableSerializer(new SaveFilter());
return serializer.Serialize(tableContent);
}
private ConnectionTreeModel CreateConnectionTreeModel()
{
var builder = new ConnectionTreeModelBuilder();
return builder.Build();
}
}
}

View File

@@ -4,6 +4,7 @@ using mRemoteNG.Container;
using mRemoteNG.Security;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
using mRemoteNGTests.TestHelpers;
using NUnit.Framework;
namespace mRemoteNGTests.Config.Serializers
@@ -20,13 +21,6 @@ namespace mRemoteNGTests.Config.Serializers
_dataTableSerializer = new DataTableSerializer(_saveFilter);
}
[TearDown]
public void Teardown()
{
_saveFilter = null;
_dataTableSerializer = null;
}
[Test]
public void AllItemsSerialized()
{
@@ -35,6 +29,14 @@ namespace mRemoteNGTests.Config.Serializers
Assert.That(dataTable.Rows.Count, Is.EqualTo(3));
}
[Test]
public void ReturnsEmptyDataTableWhenGivenEmptyConnectionTreeModel()
{
var model = new ConnectionTreeModel();
var dataTable = _dataTableSerializer.Serialize(model);
Assert.That(dataTable.Rows.Count, Is.EqualTo(0));
}
[Test]
public void UsernameSerializedWhenSaveSecurityAllowsIt()
{
@@ -109,20 +111,18 @@ namespace mRemoteNGTests.Config.Serializers
Assert.That(dataTable.Rows[0]["InheritUsername"], Is.False);
}
[Test]
public void CanSerializeEmptyConnectionInfo()
{
var dataTable = _dataTableSerializer.Serialize(new ConnectionInfo());
Assert.That(dataTable.Rows.Count, Is.EqualTo(1));
}
private ConnectionTreeModel CreateConnectionTreeModel()
{
var model = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var folder1 = new ContainerInfo {Name = "folder1", Username = "user1", Domain = "domain1", Password = "password1"};
var con1 = new ConnectionInfo {Name = "Con1", Username = "user1", Domain = "domain1", Password = "password1" };
var con2 = new ConnectionInfo {Name = "Con2", Username = "user2", Domain = "domain2", Password = "password2" };
root.AddChild(folder1);
root.AddChild(con2);
folder1.AddChild(con1);
model.AddRootNode(root);
return model;
var builder = new ConnectionTreeModelBuilder();
return builder.Build();
}
}
}

View File

@@ -48,6 +48,14 @@ namespace mRemoteNGTests.Connection
Assert.That(secondConnection.Domain, Is.EqualTo(_connectionInfo.Domain));
}
[Test]
public void CloneDoesNotSetParentOfNewConnectionInfo()
{
_connectionInfo.SetParent(new ContainerInfo());
var clonedConnection = _connectionInfo.Clone();
Assert.That(clonedConnection.Parent, Is.Null);
}
[Test]
public void CopyFromCopiesProperties()
{

View File

@@ -0,0 +1,57 @@
using System.Collections;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Connection.Protocol;
using mRemoteNG.Tools;
using mRemoteNG.UI.Window;
using NUnit.Framework;
using WeifenLuo.WinFormsUI.Docking;
namespace mRemoteNGTests.Connection.Protocol
{
public class IntegratedProgramTests
{
private readonly ExternalTool _extTool = new ExternalTool
{
DisplayName = "notepad",
FileName = @"%windir%\system32\notepad.exe",
Arguments = "",
TryIntegrate = true
};
[Test]
public void CanStartExternalApp()
{
SetExternalToolList(_extTool);
var sut = new IntegratedProgram();
sut.InterfaceControl = BuildInterfaceControl("notepad", sut);
sut.Initialize();
var appStarted = sut.Connect();
sut.Disconnect();
Assert.That(appStarted);
}
[Test]
public void ConnectingToExternalAppThatDoesntExistDoesNothing()
{
SetExternalToolList(_extTool);
var sut = new IntegratedProgram();
sut.InterfaceControl = BuildInterfaceControl("doesntExist", sut);
var appInitialized = sut.Initialize();
Assert.That(appInitialized, Is.False);
}
private void SetExternalToolList(ExternalTool externalTool)
{
Runtime.ExternalTools = new ArrayList {externalTool};
}
private InterfaceControl BuildInterfaceControl(string extAppName, ProtocolBase sut)
{
var connectionWindow = new ConnectionWindow(new DockContent());
var connectionInfo = new ConnectionInfo {ExtApp = extAppName};
return new InterfaceControl(connectionWindow, sut, connectionInfo);
}
}
}

View File

@@ -263,6 +263,14 @@ namespace mRemoteNGTests.Container
Assert.That(clone.ConstantID, Is.Not.EqualTo(_containerInfo.ConstantID));
}
[Test]
public void ClonedContainerDoesNotHaveParentSet()
{
_containerInfo.SetParent(new ContainerInfo());
var clone = _containerInfo.Clone();
Assert.That(clone.Parent, Is.Null);
}
[Test]
public void ClonedContainerContainsClonedChildren()
{

View File

@@ -0,0 +1,25 @@
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Tree;
using mRemoteNG.Tree.Root;
namespace mRemoteNGTests.TestHelpers
{
public class ConnectionTreeModelBuilder
{
public ConnectionTreeModel Build()
{
var model = new ConnectionTreeModel();
var root = new RootNodeInfo(RootNodeType.Connection);
var folder1 = new ContainerInfo { Name = "folder1", Username = "user1", Domain = "domain1", Password = "password1" };
var con1 = new ConnectionInfo { Name = "Con1", Username = "user1", Domain = "domain1", Password = "password1" };
var con2 = new ConnectionInfo { Name = "Con2", Username = "user2", Domain = "domain2", Password = "password2" };
root.AddChild(folder1);
root.AddChild(con2);
folder1.AddChild(con1);
model.AddRootNode(root);
return model;
}
}
}

View File

@@ -37,7 +37,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug Portable|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug Portable\</OutputPath>
<OutputPath>bin\Debug Portable\</OutputPath>
<DefineConstants>TRACE;DEBUG;PORTABLE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
@@ -45,7 +45,7 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release Portable|x86'">
<OutputPath>bin\x86\Release Portable\</OutputPath>
<OutputPath>bin\Release Portable\</OutputPath>
<DefineConstants>TRACE;PORTABLE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
@@ -62,13 +62,11 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\mRemoteV1\References\log4net.dll</HintPath>
</Reference>
<Reference Include="NSubstitute, Version=1.10.0.0, Culture=neutral, PublicKeyToken=92dd2e9066daa5ca, processorArchitecture=MSIL">
<HintPath>..\packages\NSubstitute.1.10.0.0\lib\net45\NSubstitute.dll</HintPath>
<Private>True</Private>
<Reference Include="NSubstitute, Version=2.0.3.0, Culture=neutral, PublicKeyToken=92dd2e9066daa5ca, processorArchitecture=MSIL">
<HintPath>..\packages\NSubstitute.2.0.3\lib\net45\NSubstitute.dll</HintPath>
</Reference>
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
<Private>True</Private>
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
<HintPath>..\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
</Reference>
<Reference Include="NUnitForms">
<HintPath>nUnitForms\bin\NUnitForms.dll</HintPath>
@@ -111,6 +109,7 @@
<Compile Include="App\LoggerTests.cs" />
<Compile Include="App\UpdaterTests.cs" />
<Compile Include="BinaryFileTests.cs" />
<Compile Include="Config\Serializers\DataTableDeserializerTests.cs" />
<Compile Include="Config\Serializers\DataTableSerializerTests.cs" />
<Compile Include="Config\Serializers\PortScanDeserializerTests.cs" />
<Compile Include="Config\Serializers\PuttyConnectionManagerDeserializerTests.cs" />
@@ -124,11 +123,13 @@
<Compile Include="Config\Serializers\XmlRootNodeSerializerTests.cs" />
<Compile Include="Connection\AbstractConnectionInfoDataTests.cs" />
<Compile Include="Connection\ConnectionInfoComparerTests.cs" />
<Compile Include="Connection\Protocol\IntegratedProgramTests.cs" />
<Compile Include="Connection\Protocol\ProtocolListTests.cs" />
<Compile Include="IntegrationTests\XmlSerializationLifeCycleTests.cs" />
<Compile Include="Security\Authentication\PasswordAuthenticatorTests.cs" />
<Compile Include="Security\KeyDerivation\Pkcs5S2KeyGeneratorTests.cs" />
<Compile Include="Security\SecureStringExtensionsTests.cs" />
<Compile Include="TestHelpers\ConnectionTreeModelBuilder.cs" />
<Compile Include="Tools\ExternalToolsArgumentParserTests.cs" />
<Compile Include="Tree\ClickHandlers\TreeNodeCompositeClickHandlerTests.cs" />
<Compile Include="Tree\ConnectionTreeDragAndDropHandlerTests.cs" />

View File

@@ -3,7 +3,7 @@
<package id="BouncyCastle" version="1.8.1" targetFramework="net45" />
<package id="DockPanelSuite" version="2.10.0" targetFramework="net45" />
<package id="DockPanelSuite.ThemeVS2012Light" version="2.10.0" targetFramework="net45" />
<package id="NSubstitute" version="1.10.0.0" targetFramework="net45" />
<package id="NUnit" version="3.5.0" targetFramework="net45" />
<package id="NSubstitute" version="2.0.3" targetFramework="net45" />
<package id="NUnit" version="3.8.1" targetFramework="net45" />
<package id="ObjectListView.Official" version="2.9.1" targetFramework="net45" />
</packages>

View File

@@ -20,6 +20,7 @@ Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug Portable|x86 = Debug Portable|x86
Debug|x86 = Debug|x86
Release Installer|x86 = Release Installer|x86
Release Portable|x86 = Release Portable|x86
Release|x86 = Release|x86
EndGlobalSection
@@ -28,6 +29,8 @@ Global
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug Portable|x86.Build.0 = Debug Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.ActiveCfg = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Debug|x86.Build.0 = Debug|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.ActiveCfg = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Installer|x86.Build.0 = Release|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.ActiveCfg = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release Portable|x86.Build.0 = Release Portable|x86
{4934A491-40BC-4E5B-9166-EA1169A220F6}.Release|x86.ActiveCfg = Release|x86
@@ -36,6 +39,8 @@ Global
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug Portable|x86.Build.0 = Debug Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.ActiveCfg = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Debug|x86.Build.0 = Debug|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.ActiveCfg = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Installer|x86.Build.0 = Release|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.ActiveCfg = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release Portable|x86.Build.0 = Release Portable|x86
{1453B37F-8621-499E-B0B2-6091F76DC0BB}.Release|x86.ActiveCfg = Release|x86
@@ -43,11 +48,14 @@ Global
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug Portable|x86.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.ActiveCfg = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Debug|x86.Build.0 = Debug|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Installer|x86.Build.0 = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release Portable|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x86.ActiveCfg = Release|x86
{5423D985-CB48-4344-B47F-E8C6D60C8B04}.Release|x86.Build.0 = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug Portable|x86.ActiveCfg = Debug Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Debug|x86.ActiveCfg = Debug|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.ActiveCfg = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Installer|x86.Build.0 = Release|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release Portable|x86.ActiveCfg = Release Portable|x86
{F0168B9F-6815-40DF-BA53-46CEE7683B68}.Release|x86.ActiveCfg = Release|x86
EndGlobalSection

View File

@@ -1,4 +1,5 @@
using log4net;
using System.Diagnostics;
using log4net;
using log4net.Appender;
using log4net.Config;
#if !PORTABLE
@@ -45,14 +46,23 @@ namespace mRemoteNG.App
private static string BuildLogFilePath()
{
if (!Settings.Default.WriteLogFile)
return "";
#if !PORTABLE
var logFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.ProductName);
#else
var logFilePath = Application.StartupPath;
#endif
var logFileName = Path.ChangeExtension(Application.ProductName, ".log");
var logFile = Path.Combine(logFilePath, logFileName);
return logFile;
if (logFileName != null)
{
var logFile = Path.Combine(logFilePath, logFileName);
return logFile;
}
Debug.Print("Error: Could not determine log file path.");
return "";
}
}
}

View File

@@ -1,6 +1,9 @@
using System;
using System.Drawing;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
#pragma warning disable 169
namespace mRemoteNG.App
@@ -42,11 +45,17 @@ namespace mRemoteNG.App
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, System.Text.StringBuilder lParam);
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, StringBuilder lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, string lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage([In] IntPtr hWnd, [In] uint msg, [Out] StringBuilder wParam, [In] IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool SetForegroundWindow(IntPtr hWnd);
@@ -76,6 +85,10 @@ namespace mRemoteNG.App
[DllImport("user32", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern bool SetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("kernel32", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal static extern bool CloseHandle(IntPtr handle);
#endregion
#region Structures
@@ -286,7 +299,10 @@ namespace mRemoteNG.App
public const int WA_ACTIVE = 0x1;
/// <summary>
///
/// Sent to both the window being activated and the window being deactivated.
/// If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the
/// top-level window being deactivated, then to the window procedure of the top-level window being activated. If the
/// windows use different input queues, the message is sent asynchronously, so the window is activated immediately.
/// </summary>
public const int WA_CLICKACTIVE = 0x2;
#endregion
@@ -455,6 +471,12 @@ namespace mRemoteNG.App
public const int VK_C = 0x67;
#endregion
#region EM
public const uint ECM_FIRST = 0x1500;
public const uint EM_SETCUEBANNER = ECM_FIRST + 1;
public const uint EM_GETCUEBANNER = ECM_FIRST + 2;
#endregion
#region LB
public const int LB_ERR = -1;
public const int LB_SELECTSTRING = 0x18C;

View File

@@ -37,7 +37,7 @@ namespace mRemoteNG.App
public static bool IsConnectionsFileLoaded { get; set; }
public static RemoteConnectionsSyncronizer RemoteConnectionsSyncronizer { get; set; }
// ReSharper disable once UnusedAutoPropertyAccessor.Local
private static DateTime LastSqlUpdate { get; set; }
public static DateTime LastSqlUpdate { get; set; }
public static ArrayList ExternalTools { get; set; } = new ArrayList();
public static SecureString EncryptionKey { get; set; } = new RootNodeInfo(RootNodeType.Connection).PasswordString.ConvertToSecureString();
public static ConnectionTreeModel ConnectionTreeModel
@@ -283,7 +283,7 @@ namespace mRemoteNG.App
connectionsLoader.ConnectionFileName = GetStartupConnectionFileName();
}
CreateBackupFile(Convert.ToString(connectionsLoader.ConnectionFileName));
CreateBackupFile(connectionsLoader.ConnectionFileName);
}
connectionsLoader.UseDatabase = Settings.Default.UseSQLServer;
@@ -334,7 +334,7 @@ namespace mRemoteNG.App
if (ex is FileNotFoundException && !withDialog)
{
MessageCollector.AddExceptionMessage(string.Format(Language.strConnectionsFileCouldNotBeLoadedNew, connectionsLoader.ConnectionFileName), ex, MessageClass.InformationMsg);
NewConnections(Convert.ToString(connectionsLoader.ConnectionFileName));
NewConnections(connectionsLoader.ConnectionFileName);
return;
}
@@ -465,11 +465,11 @@ namespace mRemoteNG.App
if (Settings.Default.UseSQLServer)
{
connectionsSaver.SaveFormat = ConnectionsSaver.Format.SQL;
connectionsSaver.SQLHost = Convert.ToString(Settings.Default.SQLHost);
connectionsSaver.SQLDatabaseName = Convert.ToString(Settings.Default.SQLDatabaseName);
connectionsSaver.SQLUsername = Convert.ToString(Settings.Default.SQLUser);
connectionsSaver.SQLHost = Settings.Default.SQLHost;
connectionsSaver.SQLDatabaseName = Settings.Default.SQLDatabaseName;
connectionsSaver.SQLUsername = Settings.Default.SQLUser;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
connectionsSaver.SQLPassword = cryptographyProvider.Decrypt(Convert.ToString(Settings.Default.SQLPass), EncryptionKey);
connectionsSaver.SQLPassword = cryptographyProvider.Decrypt(Settings.Default.SQLUser, EncryptionKey);
}
connectionsSaver.SaveConnections();

View File

@@ -42,8 +42,6 @@ namespace mRemoteNG.App
ParseCommandLineArgs();
IeBrowserEmulation.Register();
GetConnectionIcons();
DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, a=>"ConDefault"+a);
DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, a=>"InhDefault"+a);
}
private static void GetConnectionIcons()
@@ -76,7 +74,7 @@ namespace mRemoteNG.App
{
var osData = GetOperatingSystemData();
var architecture = GetArchitectureData();
Logger.Instance.InfoFormat(string.Join(" ", Array.FindAll(new[] { osData, architecture }, s => !string.IsNullOrEmpty(Convert.ToString(s)))));
Logger.Instance.InfoFormat(string.Join(" ", Array.FindAll(new[] { osData, architecture }, s => !string.IsNullOrEmpty(s))));
}
private static string GetOperatingSystemData()
@@ -214,10 +212,37 @@ namespace mRemoteNG.App
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("GetUpdateInfoCompleted() failed.", ex, MessageClass.ErrorMsg, true);
Runtime.MessageCollector.AddExceptionMessage("GetUpdateInfoCompleted() failed.", ex);
}
}
/// <summary>
/// Returns a path to a file connections XML file for a given absolute or relative path
/// </summary>
/// <param name="ConsParam">The absolute or relative path to the connection XML file</param>
/// <returns>string or null</returns>
private static string GetCustomConsPath(string ConsParam)
{
// early exit condition
if (string.IsNullOrEmpty(ConsParam))
return null;
// trim invalid characters for the Combine method (see: https://msdn.microsoft.com/en-us/library/fyy7a5kt.aspx#Anchor_2)
ConsParam = ConsParam.Trim().TrimStart('\\').Trim();
// fallback paths
if (File.Exists(ConsParam))
return ConsParam;
if (File.Exists(Path.Combine(GeneralAppInfo.HomePath, ConsParam)))
return GeneralAppInfo.HomePath + Path.DirectorySeparatorChar + ConsParam;
if (File.Exists(Path.Combine(ConnectionsFileInfo.DefaultConnectionsPath, ConsParam)))
return ConnectionsFileInfo.DefaultConnectionsPath + Path.DirectorySeparatorChar + ConsParam;
// default case
return null;
}
private static void ParseCommandLineArgs()
{
@@ -282,29 +307,12 @@ namespace mRemoteNG.App
NoReconnectParam = "norc";
}
if (!string.IsNullOrEmpty(ConsParam))
// Handle custom connection file location
var consPathFromParam = GetCustomConsPath(ConsParam);
if (consPathFromParam != null)
{
if (File.Exists(cmd[ConsParam]) == false)
{
if (File.Exists(GeneralAppInfo.HomePath + "\\" + cmd[ConsParam]))
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = GeneralAppInfo.HomePath + "\\" + cmd[ConsParam];
return;
}
if (File.Exists(ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam]))
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = ConnectionsFileInfo.DefaultConnectionsPath + "\\" + cmd[ConsParam];
return;
}
}
else
{
Settings.Default.LoadConsFromCustomLocation = true;
Settings.Default.CustomConsPath = cmd[ConsParam];
return;
}
Settings.Default.CustomConsPath = consPathFromParam;
Settings.Default.LoadConsFromCustomLocation = true;
}
if (!string.IsNullOrEmpty(ResetPosParam))
@@ -329,6 +337,8 @@ namespace mRemoteNG.App
{
Settings.Default.ResetToolbars = true;
}
Settings.Default.Save();
}
catch (Exception ex)
{

View File

@@ -27,6 +27,9 @@ namespace mRemoteNG.App.Update
char[] keyValueSeparators = { ':', '=' };
char[] commentCharacters = { '#', ';', '\'' };
// no separators means no valid update data...
if (content.Trim().IndexOfAny(keyValueSeparators) == -1) return;
using (var sr = new StringReader(content))
{
string line;
@@ -43,6 +46,10 @@ namespace mRemoteNG.App.Update
if (parts.Length != 2)
continue;
// make sure we have valid data in both parts before adding to the collection. If either part is empty, then it's not valid data.
if(string.IsNullOrEmpty(parts[0].Trim()) || string.IsNullOrEmpty(parts[1].Trim()))
continue;
Items.Add(parts[0].Trim(), parts[1].Trim());
}
}

View File

@@ -57,7 +57,15 @@ namespace mRemoteNG.Config.Connections
private bool DatabaseIsMoreUpToDateThanUs()
{
return GetLastUpdateTimeFromDbResponse() > _lastUpdateTime;
var lastUpdateInDb = GetLastUpdateTimeFromDbResponse();
var IAmTheLastoneUpdated = CheckIfIAmTheLastOneUpdated(lastUpdateInDb);
return (lastUpdateInDb > _lastUpdateTime && !IAmTheLastoneUpdated);
}
private bool CheckIfIAmTheLastOneUpdated(DateTime lastUpdateInDb)
{
DateTime LastSqlUpdateWithoutMilliseconds = new DateTime(Runtime.LastSqlUpdate.Ticks - (Runtime.LastSqlUpdate.Ticks % TimeSpan.TicksPerSecond), Runtime.LastSqlUpdate.Kind);
return lastUpdateInDb == LastSqlUpdateWithoutMilliseconds;
}
private DateTime GetLastUpdateTimeFromDbResponse()

View File

@@ -35,7 +35,7 @@ namespace mRemoteNG.Config.Import
var connectionTreeModel = xmlConnectionsDeserializer.Deserialize(true);
var rootImportContainer = new ContainerInfo { Name = Path.GetFileNameWithoutExtension(fileName) };
rootImportContainer.Children.AddRange(connectionTreeModel.RootNodes.First().Children);
rootImportContainer.AddChildRange(connectionTreeModel.RootNodes.First().Children.ToArray());
destinationContainer.AddChild(rootImportContainer);
}
}

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using mRemoteNG.Connection;
using mRemoteNG.Tree.Root;
@@ -42,7 +43,8 @@ namespace mRemoteNG.Config.Putty
private IEnumerable<PuttySessionInfo> GetSessionToRemove(IEnumerable<string> sessionNamesFromProvider)
{
var currentlyKnownSessionNames = Sessions.Select(session => session.Name);
var sessionNamesToRemove = currentlyKnownSessionNames.Except(sessionNamesFromProvider);
var normalizedSessionNames = sessionNamesFromProvider.Select(HttpUtility.UrlDecode);
var sessionNamesToRemove = currentlyKnownSessionNames.Except(normalizedSessionNames);
return Sessions.Where(session => sessionNamesToRemove.Contains(session.Name));
}

View File

@@ -31,7 +31,7 @@ namespace mRemoteNG.Config.Putty
if (raw && !sessionNames.Contains("Default%20Settings"))
sessionNames.Insert(0, "Default%20Settings");
else if (!sessionNames.Contains("Default Settings"))
else if (!raw && !sessionNames.Contains("Default Settings"))
sessionNames.Insert(0, "Default Settings");
return sessionNames.ToArray();

View File

@@ -43,10 +43,16 @@ namespace mRemoteNG.Config.Serializers
var nodeList = new List<ConnectionInfo>();
foreach (DataRow row in _dataTable.Rows)
{
if ((string)row["Type"] == "Connection")
// ReSharper disable once SwitchStatementMissingSomeCases
switch ((string)row["Type"])
{
case "Connection":
nodeList.Add(DeserializeConnectionInfo(row));
else if ((string)row["Type"] == "Container")
break;
case "Container":
nodeList.Add(DeserializeContainerInfo(row));
break;
}
}
return nodeList;
}
@@ -69,8 +75,15 @@ namespace mRemoteNG.Config.Serializers
{
connectionInfo.Name = (string)dataRow["Name"];
connectionInfo.ConstantID = (string)dataRow["ConstantID"];
// This throws a NPE - Parent is a connectionInfo object which will be null at this point.
// The Parent object is linked properly later in CreateNodeHierarchy()
//connectionInfo.Parent.ConstantID = (string)dataRow["ParentID"];
//connectionInfo is ContainerInfo ? ((ContainerInfo)connectionInfo).IsExpanded.ToString() : "" = dataRow["Expanded"];
var info = connectionInfo as ContainerInfo;
if(info != null)
info.IsExpanded = (bool)dataRow["Expanded"];
connectionInfo.Description = (string)dataRow["Description"];
connectionInfo.Icon = (string)dataRow["Icon"];
connectionInfo.Panel = (string)dataRow["Panel"];
@@ -195,7 +208,7 @@ namespace mRemoteNG.Config.Serializers
var id = (string) row["ConstantID"];
var connectionInfo = connectionList.First(node => node.ConstantID == id);
var parentId = (string) row["ParentID"];
if (parentId == "0")
if (parentId == "0" || connectionList.All(node => node.ConstantID != parentId))
rootNode.AddChild(connectionInfo);
else
(connectionList.First(node => node.ConstantID == parentId) as ContainerInfo)?.AddChild(connectionInfo);

View File

@@ -25,147 +25,162 @@ namespace mRemoteNG.Config.Serializers
public DataTable Serialize(ConnectionTreeModel connectionTreeModel)
{
var rootNode = (RootNodeInfo)connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
return Serialize(rootNode);
try
{
_dataTable = BuildTable();
_currentNodeIndex = 0;
var rootNode = connectionTreeModel.RootNodes.First(node => node is RootNodeInfo);
return Serialize(rootNode);
}
catch
{
return _dataTable;
}
}
public DataTable Serialize(ConnectionInfo serializationTarget)
{
_dataTable = new DataTable(TableName);
CreateSchema();
SetPrimaryKey();
_dataTable = BuildTable();
_currentNodeIndex = 0;
SerializeNodesRecursive(serializationTarget);
return _dataTable;
}
private void CreateSchema()
private DataTable BuildTable()
{
// Note: these columns must be defined in the same order that they exist in the DB
_dataTable.Columns.Add("ID", typeof(int));
_dataTable.Columns[0].AutoIncrement = true;
_dataTable.Columns.Add("ConstantID", typeof(string));
_dataTable.Columns.Add("PositionID", typeof(int));
_dataTable.Columns.Add("ParentID", typeof(string));
_dataTable.Columns.Add("LastChange", typeof(SqlDateTime));
_dataTable.Columns.Add("Name", typeof(string));
_dataTable.Columns.Add("Type", typeof(string));
_dataTable.Columns.Add("Expanded", typeof(bool));
_dataTable.Columns.Add("Description", typeof(string));
_dataTable.Columns.Add("Icon", typeof(string));
_dataTable.Columns.Add("Panel", typeof(string));
_dataTable.Columns.Add("Username", typeof(string));
_dataTable.Columns.Add("DomainName", typeof(string));
_dataTable.Columns.Add("Password", typeof(string));
_dataTable.Columns.Add("Hostname", typeof(string));
_dataTable.Columns.Add("Protocol", typeof(string));
_dataTable.Columns.Add("PuttySession", typeof(string));
_dataTable.Columns.Add("Port", typeof(int));
_dataTable.Columns.Add("ConnectToConsole", typeof(bool));
_dataTable.Columns.Add("UseCredSsp", typeof(bool));
_dataTable.Columns.Add("RenderingEngine", typeof(string));
_dataTable.Columns.Add("ICAEncryptionStrength", typeof(string));
_dataTable.Columns.Add("RDPAuthenticationLevel", typeof(string));
_dataTable.Columns.Add("Colors", typeof(string));
_dataTable.Columns.Add("Resolution", typeof(string));
_dataTable.Columns.Add("DisplayWallpaper", typeof(bool));
_dataTable.Columns.Add("DisplayThemes", typeof(bool));
_dataTable.Columns.Add("EnableFontSmoothing", typeof(bool));
_dataTable.Columns.Add("EnableDesktopComposition", typeof(bool));
_dataTable.Columns.Add("CacheBitmaps", typeof(bool));
_dataTable.Columns.Add("RedirectDiskDrives", typeof(bool));
_dataTable.Columns.Add("RedirectPorts", typeof(bool));
_dataTable.Columns.Add("RedirectPrinters", typeof(bool));
_dataTable.Columns.Add("RedirectSmartCards", typeof(bool));
_dataTable.Columns.Add("RedirectSound", typeof(string));
_dataTable.Columns.Add("RedirectKeys", typeof(bool));
_dataTable.Columns.Add("Connected", typeof(bool));
_dataTable.Columns.Add("PreExtApp", typeof(string));
_dataTable.Columns.Add("PostExtApp", typeof(string));
_dataTable.Columns.Add("MacAddress", typeof(string));
_dataTable.Columns.Add("UserField", typeof(string));
_dataTable.Columns.Add("ExtApp", typeof(string));
_dataTable.Columns.Add("VNCCompression", typeof(string));
_dataTable.Columns.Add("VNCEncoding", typeof(string));
_dataTable.Columns.Add("VNCAuthMode", typeof(string));
_dataTable.Columns.Add("VNCProxyType", typeof(string));
_dataTable.Columns.Add("VNCProxyIP", typeof(string));
_dataTable.Columns.Add("VNCProxyPort", typeof(int));
_dataTable.Columns.Add("VNCProxyUsername", typeof(string));
_dataTable.Columns.Add("VNCProxyPassword", typeof(string));
_dataTable.Columns.Add("VNCColors", typeof(string));
_dataTable.Columns.Add("VNCSmartSizeMode", typeof(string));
_dataTable.Columns.Add("VNCViewOnly", typeof(bool));
_dataTable.Columns.Add("RDGatewayUsageMethod", typeof(string));
_dataTable.Columns.Add("RDGatewayHostname", typeof(string));
_dataTable.Columns.Add("RDGatewayUseConnectionCredentials", typeof(string));
_dataTable.Columns.Add("RDGatewayUsername", typeof(string));
_dataTable.Columns.Add("RDGatewayPassword", typeof(string));
_dataTable.Columns.Add("RDGatewayDomain", typeof(string));
_dataTable.Columns.Add("InheritCacheBitmaps", typeof(bool));
_dataTable.Columns.Add("InheritColors", typeof(bool));
_dataTable.Columns.Add("InheritDescription", typeof(bool));
_dataTable.Columns.Add("InheritDisplayThemes", typeof(bool));
_dataTable.Columns.Add("InheritDisplayWallpaper", typeof(bool));
_dataTable.Columns.Add("InheritEnableFontSmoothing", typeof(bool));
_dataTable.Columns.Add("InheritEnableDesktopComposition", typeof(bool));
_dataTable.Columns.Add("InheritDomain", typeof(bool));
_dataTable.Columns.Add("InheritIcon", typeof(bool));
_dataTable.Columns.Add("InheritPanel", typeof(bool));
_dataTable.Columns.Add("InheritPassword", typeof(bool));
_dataTable.Columns.Add("InheritPort", typeof(bool));
_dataTable.Columns.Add("InheritProtocol", typeof(bool));
_dataTable.Columns.Add("InheritPuttySession", typeof(bool));
_dataTable.Columns.Add("InheritRedirectDiskDrives", typeof(bool));
_dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
_dataTable.Columns.Add("InheritRedirectPorts", typeof(bool));
_dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool));
_dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool));
_dataTable.Columns.Add("InheritRedirectSound", typeof(bool));
_dataTable.Columns.Add("InheritResolution", typeof(bool));
_dataTable.Columns.Add("InheritUseConsoleSession", typeof(bool));
_dataTable.Columns.Add("InheritUseCredSsp", typeof(bool));
_dataTable.Columns.Add("InheritRenderingEngine", typeof(bool));
_dataTable.Columns.Add("InheritICAEncryptionStrength", typeof(bool));
_dataTable.Columns.Add("InheritRDPAuthenticationLevel", typeof(bool));
_dataTable.Columns.Add("InheritUsername", typeof(bool));
_dataTable.Columns.Add("InheritPreExtApp", typeof(bool));
_dataTable.Columns.Add("InheritPostExtApp", typeof(bool));
_dataTable.Columns.Add("InheritMacAddress", typeof(bool));
_dataTable.Columns.Add("InheritUserField", typeof(bool));
_dataTable.Columns.Add("InheritExtApp", typeof(bool));
_dataTable.Columns.Add("InheritVNCCompression", typeof(bool));
_dataTable.Columns.Add("InheritVNCEncoding", typeof(bool));
_dataTable.Columns.Add("InheritVNCAuthMode", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyType", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyIP", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyPort", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyUsername", typeof(bool));
_dataTable.Columns.Add("InheritVNCProxyPassword", typeof(bool));
_dataTable.Columns.Add("InheritVNCColors", typeof(bool));
_dataTable.Columns.Add("InheritVNCSmartSizeMode", typeof(bool));
_dataTable.Columns.Add("InheritVNCViewOnly", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayUsageMethod", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayHostname", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayUseConnectionCredentials", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayUsername", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayPassword", typeof(bool));
_dataTable.Columns.Add("InheritRDGatewayDomain", typeof(bool));
_dataTable.Columns.Add("LoadBalanceInfo", typeof(string));
_dataTable.Columns.Add("AutomaticResize", typeof(bool));
_dataTable.Columns.Add("InheritLoadBalanceInfo", typeof(bool));
_dataTable.Columns.Add("InheritAutomaticResize", typeof(bool));
_dataTable.Columns.Add("RDPMinutesToIdleTimeout", typeof(int));
_dataTable.Columns.Add("RDPAlertIdleTimeout", typeof(bool));
_dataTable.Columns.Add("SoundQuality", typeof(string));
_dataTable.Columns.Add("InheritRDPMinutesToIdleTimeout", typeof(bool));
_dataTable.Columns.Add("InheritRDPAlertIdleTimeout", typeof(bool));
_dataTable.Columns.Add("InheritSoundQuality", typeof(bool));
var dataTable = new DataTable(TableName);
CreateSchema(dataTable);
SetPrimaryKey(dataTable);
return dataTable;
}
private void SetPrimaryKey()
private void CreateSchema(DataTable dataTable)
{
_dataTable.PrimaryKey = new[] { _dataTable.Columns["ConstantID"] };
// Note: these columns must be defined in the same order that they exist in the DB
dataTable.Columns.Add("ID", typeof(int));
dataTable.Columns[0].AutoIncrement = true;
dataTable.Columns.Add("ConstantID", typeof(string));
dataTable.Columns.Add("PositionID", typeof(int));
dataTable.Columns.Add("ParentID", typeof(string));
dataTable.Columns.Add("LastChange", typeof(SqlDateTime));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("Type", typeof(string));
dataTable.Columns.Add("Expanded", typeof(bool));
dataTable.Columns.Add("Description", typeof(string));
dataTable.Columns.Add("Icon", typeof(string));
dataTable.Columns.Add("Panel", typeof(string));
dataTable.Columns.Add("Username", typeof(string));
dataTable.Columns.Add("DomainName", typeof(string));
dataTable.Columns.Add("Password", typeof(string));
dataTable.Columns.Add("Hostname", typeof(string));
dataTable.Columns.Add("Protocol", typeof(string));
dataTable.Columns.Add("PuttySession", typeof(string));
dataTable.Columns.Add("Port", typeof(int));
dataTable.Columns.Add("ConnectToConsole", typeof(bool));
dataTable.Columns.Add("UseCredSsp", typeof(bool));
dataTable.Columns.Add("RenderingEngine", typeof(string));
dataTable.Columns.Add("ICAEncryptionStrength", typeof(string));
dataTable.Columns.Add("RDPAuthenticationLevel", typeof(string));
dataTable.Columns.Add("Colors", typeof(string));
dataTable.Columns.Add("Resolution", typeof(string));
dataTable.Columns.Add("DisplayWallpaper", typeof(bool));
dataTable.Columns.Add("DisplayThemes", typeof(bool));
dataTable.Columns.Add("EnableFontSmoothing", typeof(bool));
dataTable.Columns.Add("EnableDesktopComposition", typeof(bool));
dataTable.Columns.Add("CacheBitmaps", typeof(bool));
dataTable.Columns.Add("RedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("RedirectPorts", typeof(bool));
dataTable.Columns.Add("RedirectPrinters", typeof(bool));
dataTable.Columns.Add("RedirectSmartCards", typeof(bool));
dataTable.Columns.Add("RedirectSound", typeof(string));
dataTable.Columns.Add("RedirectKeys", typeof(bool));
dataTable.Columns.Add("Connected", typeof(bool));
dataTable.Columns.Add("PreExtApp", typeof(string));
dataTable.Columns.Add("PostExtApp", typeof(string));
dataTable.Columns.Add("MacAddress", typeof(string));
dataTable.Columns.Add("UserField", typeof(string));
dataTable.Columns.Add("ExtApp", typeof(string));
dataTable.Columns.Add("VNCCompression", typeof(string));
dataTable.Columns.Add("VNCEncoding", typeof(string));
dataTable.Columns.Add("VNCAuthMode", typeof(string));
dataTable.Columns.Add("VNCProxyType", typeof(string));
dataTable.Columns.Add("VNCProxyIP", typeof(string));
dataTable.Columns.Add("VNCProxyPort", typeof(int));
dataTable.Columns.Add("VNCProxyUsername", typeof(string));
dataTable.Columns.Add("VNCProxyPassword", typeof(string));
dataTable.Columns.Add("VNCColors", typeof(string));
dataTable.Columns.Add("VNCSmartSizeMode", typeof(string));
dataTable.Columns.Add("VNCViewOnly", typeof(bool));
dataTable.Columns.Add("RDGatewayUsageMethod", typeof(string));
dataTable.Columns.Add("RDGatewayHostname", typeof(string));
dataTable.Columns.Add("RDGatewayUseConnectionCredentials", typeof(string));
dataTable.Columns.Add("RDGatewayUsername", typeof(string));
dataTable.Columns.Add("RDGatewayPassword", typeof(string));
dataTable.Columns.Add("RDGatewayDomain", typeof(string));
dataTable.Columns.Add("InheritCacheBitmaps", typeof(bool));
dataTable.Columns.Add("InheritColors", typeof(bool));
dataTable.Columns.Add("InheritDescription", typeof(bool));
dataTable.Columns.Add("InheritDisplayThemes", typeof(bool));
dataTable.Columns.Add("InheritDisplayWallpaper", typeof(bool));
dataTable.Columns.Add("InheritEnableFontSmoothing", typeof(bool));
dataTable.Columns.Add("InheritEnableDesktopComposition", typeof(bool));
dataTable.Columns.Add("InheritDomain", typeof(bool));
dataTable.Columns.Add("InheritIcon", typeof(bool));
dataTable.Columns.Add("InheritPanel", typeof(bool));
dataTable.Columns.Add("InheritPassword", typeof(bool));
dataTable.Columns.Add("InheritPort", typeof(bool));
dataTable.Columns.Add("InheritProtocol", typeof(bool));
dataTable.Columns.Add("InheritPuttySession", typeof(bool));
dataTable.Columns.Add("InheritRedirectDiskDrives", typeof(bool));
dataTable.Columns.Add("InheritRedirectKeys", typeof(bool));
dataTable.Columns.Add("InheritRedirectPorts", typeof(bool));
dataTable.Columns.Add("InheritRedirectPrinters", typeof(bool));
dataTable.Columns.Add("InheritRedirectSmartCards", typeof(bool));
dataTable.Columns.Add("InheritRedirectSound", typeof(bool));
dataTable.Columns.Add("InheritResolution", typeof(bool));
dataTable.Columns.Add("InheritUseConsoleSession", typeof(bool));
dataTable.Columns.Add("InheritUseCredSsp", typeof(bool));
dataTable.Columns.Add("InheritRenderingEngine", typeof(bool));
dataTable.Columns.Add("InheritICAEncryptionStrength", typeof(bool));
dataTable.Columns.Add("InheritRDPAuthenticationLevel", typeof(bool));
dataTable.Columns.Add("InheritUsername", typeof(bool));
dataTable.Columns.Add("InheritPreExtApp", typeof(bool));
dataTable.Columns.Add("InheritPostExtApp", typeof(bool));
dataTable.Columns.Add("InheritMacAddress", typeof(bool));
dataTable.Columns.Add("InheritUserField", typeof(bool));
dataTable.Columns.Add("InheritExtApp", typeof(bool));
dataTable.Columns.Add("InheritVNCCompression", typeof(bool));
dataTable.Columns.Add("InheritVNCEncoding", typeof(bool));
dataTable.Columns.Add("InheritVNCAuthMode", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyType", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyIP", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyPort", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyUsername", typeof(bool));
dataTable.Columns.Add("InheritVNCProxyPassword", typeof(bool));
dataTable.Columns.Add("InheritVNCColors", typeof(bool));
dataTable.Columns.Add("InheritVNCSmartSizeMode", typeof(bool));
dataTable.Columns.Add("InheritVNCViewOnly", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayUsageMethod", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayHostname", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayUseConnectionCredentials", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayUsername", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayPassword", typeof(bool));
dataTable.Columns.Add("InheritRDGatewayDomain", typeof(bool));
dataTable.Columns.Add("LoadBalanceInfo", typeof(string));
dataTable.Columns.Add("AutomaticResize", typeof(bool));
dataTable.Columns.Add("InheritLoadBalanceInfo", typeof(bool));
dataTable.Columns.Add("InheritAutomaticResize", typeof(bool));
dataTable.Columns.Add("RDPMinutesToIdleTimeout", typeof(int));
dataTable.Columns.Add("RDPAlertIdleTimeout", typeof(bool));
dataTable.Columns.Add("SoundQuality", typeof(string));
dataTable.Columns.Add("InheritRDPMinutesToIdleTimeout", typeof(bool));
dataTable.Columns.Add("InheritRDPAlertIdleTimeout", typeof(bool));
dataTable.Columns.Add("InheritSoundQuality", typeof(bool));
}
private void SetPrimaryKey(DataTable dataTable)
{
dataTable.PrimaryKey = new[] { dataTable.Columns["ConstantID"] };
}
private void SerializeNodesRecursive(ConnectionInfo connectionInfo)
@@ -186,7 +201,7 @@ namespace mRemoteNG.Config.Serializers
dataRow["Name"] = connectionInfo.Name;
dataRow["Type"] = connectionInfo.GetTreeNodeType().ToString();
dataRow["ConstantID"] = connectionInfo.ConstantID;
dataRow["ParentID"] = connectionInfo.Parent.ConstantID;
dataRow["ParentID"] = connectionInfo.Parent?.ConstantID ?? "";
dataRow["PositionID"] = _currentNodeIndex;
dataRow["LastChange"] = (SqlDateTime)DateTime.Now;
var info = connectionInfo as ContainerInfo;

View File

@@ -78,7 +78,6 @@ namespace mRemoteNG.Connection
var newConnectionInfo = new ConnectionInfo();
newConnectionInfo.CopyFrom(this);
newConnectionInfo.ConstantID = MiscTools.CreateConstantID();
newConnectionInfo.SetParent(Parent);
newConnectionInfo.Inheritance = Inheritance.Clone();
return newConnectionInfo;
}
@@ -172,7 +171,7 @@ namespace mRemoteNG.Connection
{
var inheritType = Inheritance.GetType();
var inheritPropertyInfo = inheritType.GetProperty(propertyName);
var inheritPropertyValue = Convert.ToBoolean(inheritPropertyInfo.GetValue(Inheritance, null));
var inheritPropertyValue = inheritPropertyInfo != null && Convert.ToBoolean(inheritPropertyInfo.GetValue(Inheritance, null));
return inheritPropertyValue;
}
@@ -180,15 +179,20 @@ namespace mRemoteNG.Connection
{
var connectionInfoType = Parent.GetType();
var parentPropertyInfo = connectionInfoType.GetProperty(propertyName);
if (parentPropertyInfo == null)
return default(TPropertyType); // shouldn't get here...
var parentPropertyValue = (TPropertyType)parentPropertyInfo.GetValue(Parent, null);
return parentPropertyValue;
}
private static int GetDefaultPort(ProtocolType protocol)
{
try
{
// ReSharper disable once SwitchStatementMissingSomeCases
switch (protocol)
{
case ProtocolType.RDP:

View File

@@ -18,11 +18,17 @@ namespace mRemoteNG.Connection
public void LoadFrom<TSource>(TSource sourceInstance, Func<string, string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var connectionProperties = GetProperties(_excludedProperties);
foreach (var property in connectionProperties)
{
var propertyFromSource = typeof(TSource).GetProperty(propertyNameMutator(property.Name));
if (propertyFromSource == null)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInfo-LoadFrom: Could not load {property.Name}", true);
continue;
}
var valueFromSource = propertyFromSource.GetValue(sourceInstance, null);
var descriptor = TypeDescriptor.GetProperties(Instance)[property.Name];
@@ -36,7 +42,7 @@ namespace mRemoteNG.Connection
public void SaveTo<TDestination>(TDestination destinationInstance, Func<string, string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var inheritanceProperties = GetProperties(_excludedProperties);
foreach (var property in inheritanceProperties)
{
@@ -44,6 +50,12 @@ namespace mRemoteNG.Connection
{
var propertyFromDestination = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
if (propertyFromDestination == null)
{
Runtime.MessageCollector?.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInfo-SaveTo: Could not load {property.Name}", true);
continue;
}
var convertedValue = Convert.ChangeType(localValue, propertyFromDestination.PropertyType);
propertyFromDestination.SetValue(destinationInstance, convertedValue, null);
}

View File

@@ -1,4 +1,5 @@
using System;
using mRemoteNG.App;
namespace mRemoteNG.Connection
@@ -17,11 +18,17 @@ namespace mRemoteNG.Connection
public void LoadFrom<TSource>(TSource sourceInstance, Func<string,string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var inheritanceProperties = GetProperties();
foreach (var property in inheritanceProperties)
{
var propertyFromSettings = typeof(TSource).GetProperty(propertyNameMutator(property.Name));
if (propertyFromSettings == null)
{
Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInherit-LoadFrom: Could not load {property.Name}", true);
continue;
}
var valueFromSettings = propertyFromSettings.GetValue(sourceInstance, null);
property.SetValue(Instance, valueFromSettings, null);
}
@@ -29,12 +36,18 @@ namespace mRemoteNG.Connection
public void SaveTo<TDestination>(TDestination destinationInstance, Func<string, string> propertyNameMutator = null)
{
if (propertyNameMutator == null) propertyNameMutator = (a) => a;
if (propertyNameMutator == null) propertyNameMutator = a => a;
var inheritanceProperties = GetProperties();
foreach (var property in inheritanceProperties)
{
var propertyFromSettings = typeof(TDestination).GetProperty(propertyNameMutator(property.Name));
var localValue = property.GetValue(Instance, null);
if (propertyFromSettings == null)
{
Runtime.MessageCollector?.AddMessage(Messages.MessageClass.ErrorMsg,
$"DefaultConInherit-SaveTo: Could not load {property.Name}", true);
continue;
}
propertyFromSettings.SetValue(destinationInstance, localValue, null);
}
}

View File

@@ -1,11 +1,11 @@
using mRemoteNG.App;
using mRemoteNG.Tools;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Messages;
using mRemoteNG.Tools;
namespace mRemoteNG.Connection.Protocol
@@ -21,9 +21,15 @@ namespace mRemoteNG.Connection.Protocol
#region Public Methods
public override bool Initialize()
{
if (InterfaceControl.Info == null) return base.Initialize();
if (InterfaceControl.Info == null)
return base.Initialize();
_externalTool = Runtime.GetExtAppByName(InterfaceControl.Info.ExtApp);
if (_externalTool == null)
{
Runtime.MessageCollector?.AddMessage(MessageClass.ErrorMsg, string.Format(Language.CouldNotFindExternalTool, InterfaceControl.Info.ExtApp));
return false;
}
_externalTool.ConnectionInfo = InterfaceControl.Info;
return base.Initialize();
@@ -33,7 +39,7 @@ namespace mRemoteNG.Connection.Protocol
{
try
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Attempting to start: {_externalTool.DisplayName}", true);
Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, $"Attempting to start: {_externalTool.DisplayName}", true);
if (_externalTool.TryIntegrate == false)
{
@@ -43,7 +49,7 @@ namespace mRemoteNG.Connection.Protocol
* will be called - which is just going to call IntegratedProgram.Close() again anyway...
* Close();
*/
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Assuming no other errors/exceptions occurred immediately before this message regarding {_externalTool.DisplayName}, the next \"closed by user\" message can be ignored", true);
Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, $"Assuming no other errors/exceptions occurred immediately before this message regarding {_externalTool.DisplayName}, the next \"closed by user\" message can be ignored", true);
return false;
}
@@ -63,9 +69,9 @@ namespace mRemoteNG.Connection.Protocol
_process.Exited += ProcessExited;
_process.Start();
_process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount;
_process.WaitForInputIdle(Settings.Default.MaxPuttyWaitTime * 1000);
var startTicks = Environment.TickCount;
while (_handle.ToInt32() == 0 & Environment.TickCount < startTicks + Settings.Default.MaxPuttyWaitTime * 1000)
{
_process.Refresh();
@@ -80,10 +86,10 @@ namespace mRemoteNG.Connection.Protocol
}
NativeMethods.SetParent(_handle, InterfaceControl.Handle);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, Language.strIntAppStuff, true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle), true);
Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, Language.strIntAppStuff, true);
Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppHandle, _handle), true);
Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppTitle, _process.MainWindowTitle), true);
Runtime.MessageCollector?.AddMessage(MessageClass.InformationMsg, string.Format(Language.strIntAppParentHandle, InterfaceControl.Parent.Handle), true);
Resize(this, new EventArgs());
base.Connect();
@@ -91,7 +97,7 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage(Language.strIntAppConnectionFailed, ex);
Runtime.MessageCollector?.AddExceptionMessage(Language.strIntAppConnectionFailed, ex);
return false;
}
}

View File

@@ -1,6 +1,6 @@
using System;
using System.Windows.Forms;
using System.Threading;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Tools;
@@ -153,7 +153,7 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", ex);
Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't dispose control, probably form is already closed (Connection.Protocol.Base)", ex);
}
}
@@ -172,12 +172,12 @@ namespace mRemoteNG.Connection.Protocol
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)", ex);
Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't set InterfaceControl.Parent.Tag or Dispose Interface, probably form is already closed (Connection.Protocol.Base)", ex);
}
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex);
Runtime.MessageCollector?.AddExceptionStackTrace("Couldn't Close InterfaceControl BG (Connection.Protocol.Base)", ex);
}
}

View File

@@ -80,7 +80,7 @@ namespace mRemoteNG.Connection.Protocol
}
else if (Settings.Default.EmptyCredentials == "custom")
{
username = Convert.ToString(Settings.Default.DefaultUsername);
username = Settings.Default.DefaultUsername;
}
}
@@ -93,7 +93,7 @@ namespace mRemoteNG.Connection.Protocol
if (Settings.Default.EmptyCredentials == "custom")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
password = cryptographyProvider.Decrypt(Convert.ToString(Settings.Default.DefaultPassword), Runtime.EncryptionKey);
password = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
}
}

View File

@@ -428,7 +428,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
}
else if (Settings.Default.EmptyCredentials == "custom")
{
_rdpClient.UserName = Convert.ToString(Settings.Default.DefaultUsername);
_rdpClient.UserName = Settings.Default.DefaultUsername;
}
}
else
@@ -443,7 +443,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
if (Settings.Default.DefaultPassword != "")
{
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
_rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Convert.ToString(Settings.Default.DefaultPassword), Runtime.EncryptionKey);
_rdpClient.AdvancedSettings2.ClearTextPassword = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
}
}
}
@@ -460,7 +460,7 @@ namespace mRemoteNG.Connection.Protocol.RDP
}
else if (Settings.Default.EmptyCredentials == "custom")
{
_rdpClient.Domain = Convert.ToString(Settings.Default.DefaultDomain);
_rdpClient.Domain = Settings.Default.DefaultDomain;
}
}
else

View File

@@ -179,7 +179,6 @@ namespace mRemoteNG.Container
var newContainer = new ContainerInfo();
newContainer.CopyFrom(this);
newContainer.ConstantID = MiscTools.CreateConstantID();
newContainer.SetParent(Parent);
newContainer.OpenConnections = new ProtocolList();
newContainer.Inheritance = Inheritance.Clone();
foreach (var child in Children.ToArray())

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -34,28 +34,27 @@ namespace mRemoteNG.Messages
var EnableTimer = true; // used to control if we SWITCH to the notifiation panel. Message will still be added regardless.
if (nMsg.MsgClass == MessageClass.InformationMsg)
// ReSharper disable once SwitchStatementMissingSomeCases
switch (nMsg.MsgClass)
{
AddInfoMessage(nMsg);
case MessageClass.InformationMsg:
AddInfoMessage(nMsg);
if (!Settings.Default.SwitchToMCOnInformation)
EnableTimer = false;
}
if (!Settings.Default.SwitchToMCOnInformation)
EnableTimer = false;
break;
case MessageClass.WarningMsg:
AddWarningMessage(nMsg);
if (nMsg.MsgClass == MessageClass.WarningMsg)
{
AddWarningMessage(nMsg);
if (!Settings.Default.SwitchToMCOnWarning)
EnableTimer = false;
break;
case MessageClass.ErrorMsg:
AddErrorMessage(nMsg);
if (!Settings.Default.SwitchToMCOnWarning)
EnableTimer = false;
}
if (nMsg.MsgClass == MessageClass.ErrorMsg)
{
AddErrorMessage(nMsg);
if (!Settings.Default.SwitchToMCOnError)
EnableTimer = false;
if (!Settings.Default.SwitchToMCOnError)
EnableTimer = false;
break;
}
if (OnlyLog)
@@ -95,7 +94,8 @@ namespace mRemoteNG.Messages
private static void AddErrorMessage(Message nMsg)
{
Debug.Print("Error: " + nMsg.MsgText);
Logger.Instance.Error(nMsg.MsgText);
if (Settings.Default.WriteLogFile)
Logger.Instance.Error(nMsg.MsgText);
}
private static void AddReportMessage(Message nMsg)

View File

@@ -33,7 +33,7 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// <Assembly: AssemblyVersion("1.0.*")>
[assembly: AssemblyVersion("1.75.7002.*")]
[assembly: AssemblyVersion("1.75.7011.*")]
[assembly:NeutralResourcesLanguageAttribute("en")]

View File

@@ -60,6 +60,15 @@ namespace mRemoteNG {
}
}
/// <summary>
/// Looks up a localized string similar to Could not find external tool with name &quot;{0}&quot;.
/// </summary>
internal static string CouldNotFindExternalTool {
get {
return ResourceManager.GetString("CouldNotFindExternalTool", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to About.
/// </summary>
@@ -440,7 +449,7 @@ namespace mRemoteNG {
/// <summary>
/// Looks up a localized string similar to You cannot import a normal connection file.
///Please use File - Load Connections for normal connection files!.
///Please use File - Open Connection File for normal connection files!.
/// </summary>
internal static string strCannotImportNormalSessionFile {
get {

View File

@@ -246,7 +246,7 @@
</data>
<data name="strCannotImportNormalSessionFile" xml:space="preserve">
<value>You cannot import a normal connection file.
Please use File - Load Connections for normal connection files!</value>
Please use File - Open Connection File for normal connection files!</value>
</data>
<data name="strCannotStartPortScan" xml:space="preserve">
<value>IPアドレスのフォーマットが正しくないのでポートスキャンの開始に失敗しました</value>

View File

@@ -245,7 +245,7 @@
</data>
<data name="strCannotImportNormalSessionFile" xml:space="preserve">
<value>You cannot import a normal connection file.
Please use File - Load Connections for normal connection files!</value>
Please use File - Open Connection File for normal connection files!</value>
</data>
<data name="strCannotStartPortScan" xml:space="preserve">
<value>Cannot start Port Scan, incorrect IP format!</value>
@@ -2433,4 +2433,7 @@ mRemoteNG will now quit and begin with the installation.</value>
<data name="strPropertyNameRDPAlertIdleTimeout" xml:space="preserve">
<value>Alert on Idle Disconnect</value>
</data>
<data name="CouldNotFindExternalTool" xml:space="preserve">
<value>Could not find external tool with name "{0}"</value>
</data>
</root>

Binary file not shown.

View File

@@ -5,7 +5,6 @@ using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.Messages;
using mRemoteNG.Tree;
@@ -31,7 +30,7 @@ namespace mRemoteNG.Tools
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("frmMain.AddNodeToMenu() failed", ex, MessageClass.ErrorMsg, true);
Runtime.MessageCollector.AddExceptionMessage("frmMain.AddNodeToMenu() failed", ex);
}
return dropDownList;
}
@@ -67,7 +66,7 @@ namespace mRemoteNG.Tools
}
else if (node.GetTreeNodeType() == TreeNodeType.Connection)
{
menuItem.Image = Resources.Pause;
menuItem.Image = node.OpenConnections.Count > 0 ? Resources.Play : Resources.Pause;
menuItem.Tag = node;
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using mRemoteNG.Connection;
using mRemoteNG.Security.SymmetricEncryption;
using mRemoteNG.App;
namespace mRemoteNG.Tools
{
@@ -169,12 +171,26 @@ namespace mRemoteNG.Tools
break;
case "username":
replacement = _connectionInfo.Username;
if (string.IsNullOrEmpty(replacement))
if (Settings.Default.EmptyCredentials == "windows")
replacement = Environment.UserName;
else if (Settings.Default.EmptyCredentials == "custom")
replacement = Settings.Default.DefaultUsername;
break;
case "password":
replacement = _connectionInfo.Password;
if (string.IsNullOrEmpty(replacement) && Settings.Default.EmptyCredentials == "custom")
replacement = new LegacyRijndaelCryptographyProvider()
.Decrypt(Convert.ToString(Settings.Default.DefaultPassword),
Runtime.EncryptionKey);
break;
case "domain":
replacement = _connectionInfo.Domain;
if (string.IsNullOrEmpty(replacement))
if (Settings.Default.EmptyCredentials == "windows")
replacement = Environment.UserDomainName;
else if (Settings.Default.EmptyCredentials == "custom")
replacement = Settings.Default.DefaultDomain;
break;
case "description":
replacement = _connectionInfo.Description;

View File

@@ -1,10 +1,10 @@
using Microsoft.Win32;
using mRemoteNG.App;
using mRemoteNG.Messages;
using System;
using System.Diagnostics;
using System.IO;
using System.Security.AccessControl;
using Microsoft.Win32;
using mRemoteNG.App;
using mRemoteNG.Messages;
namespace mRemoteNG.Tools
{
@@ -202,7 +202,7 @@ namespace mRemoteNG.Tools
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("IeBrowserEmulation.Register() failed.", ex, MessageClass.ErrorMsg, true);
Runtime.MessageCollector?.AddExceptionMessage("IeBrowserEmulation.Register() failed.", ex, MessageClass.ErrorMsg, true);
}
}
@@ -216,7 +216,7 @@ namespace mRemoteNG.Tools
}
catch (Exception ex)
{
Runtime.MessageCollector.AddExceptionMessage("IeBrowserEmulation.Unregister() failed.", ex, MessageClass.ErrorMsg, true);
Runtime.MessageCollector?.AddExceptionMessage("IeBrowserEmulation.Unregister() failed.", ex, MessageClass.ErrorMsg, true);
}
#endif
}

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Windows.Forms;
using mRemoteNG.App;
using mRemoteNG.Connection;
using mRemoteNG.Container;
using mRemoteNG.UI.Forms;
@@ -114,7 +115,7 @@ namespace mRemoteNG.Tools
private void ConMenItem_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left) return;
if (!(((ToolStripMenuItem) sender).Tag is ConnectionInfo)) return;
if (((ToolStripMenuItem)sender).Tag is ContainerInfo) return;
if (frmMain.Default.Visible == false)
ShowForm();
_connectionInitiator.OpenConnection((ConnectionInfo) ((ToolStripMenuItem) sender).Tag);

View File

@@ -23,14 +23,14 @@ namespace mRemoteNG.Tools
public PortScanner(IPAddress ipAddress1, IPAddress ipAddress2, int port1, int port2)
{
IPAddress ipAddressStart = IpAddressMin(ipAddress1, ipAddress2);
IPAddress ipAddressEnd = IpAddressMax(ipAddress1, ipAddress2);
var ipAddressStart = IpAddressMin(ipAddress1, ipAddress2);
var ipAddressEnd = IpAddressMax(ipAddress1, ipAddress2);
int portStart = Math.Min(port1, port2);
int portEnd = Math.Max(port1, port2);
var portStart = Math.Min(port1, port2);
var portEnd = Math.Max(port1, port2);
_ports.Clear();
for (int port = portStart; port <= portEnd; port++)
for (var port = portStart; port <= portEnd; port++)
{
_ports.Add(port);
}
@@ -59,8 +59,8 @@ namespace mRemoteNG.Tools
{
try
{
System.Net.Sockets.TcpClient tcpClient = new System.Net.Sockets.TcpClient(hostname, Convert.ToInt32(port));
tcpClient.Close();
var tcpClient = new System.Net.Sockets.TcpClient(hostname, Convert.ToInt32(port));
tcpClient.Close();
return true;
}
catch (Exception)
@@ -79,16 +79,21 @@ namespace mRemoteNG.Tools
{
hostCount = 0;
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: Starting scan of {_ipAddresses.Count} hosts...", true);
foreach (IPAddress ipAddress in _ipAddresses)
foreach (var ipAddress in _ipAddresses)
{
BeginHostScanEvent?.Invoke(ipAddress.ToString());
Ping pingSender = new Ping();
var pingSender = new Ping();
try
{
pingSender.PingCompleted += PingSender_PingCompleted;
pingSender.SendAsync(ipAddress, ipAddress);
/* https://msdn.microsoft.com/en-us/library/0e6kc029(v=vs.110).aspx
* Default timeout is 5 seconds... That's a bit long...
*/
//TODO Make timeout configurable...
pingSender.SendAsync(ipAddress, /*userToken:*/ ipAddress);
}
catch (Exception ex)
{
@@ -109,7 +114,7 @@ namespace mRemoteNG.Tools
{
// UserState is the IP Address
var ip = e.UserState.ToString();
ScanHost scanHost = new ScanHost(ip);
var scanHost = new ScanHost(ip);
hostCount++;
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: Scanning {hostCount} of {_ipAddresses.Count} hosts: {scanHost.HostIp}", true);
@@ -129,9 +134,7 @@ namespace mRemoteNG.Tools
}
catch (Exception dnsex)
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg,
$"Tools.PortScan: Could not resolve {scanHost.HostIp} {Environment.NewLine} {dnsex.Message}",
true);
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, $"Tools.PortScan: Could not resolve {scanHost.HostIp} {Environment.NewLine} {dnsex.Message}", true);
}
if (string.IsNullOrEmpty(scanHost.HostName))
@@ -139,12 +142,12 @@ namespace mRemoteNG.Tools
scanHost.HostName = scanHost.HostIp;
}
foreach (int port in _ports)
foreach (var port in _ports)
{
bool isPortOpen;
try
{
System.Net.Sockets.TcpClient tcpClient = new System.Net.Sockets.TcpClient(ip, port);
var tcpClient = new System.Net.Sockets.TcpClient(ip, port);
isPortOpen = true;
scanHost.OpenPorts.Add(port);
tcpClient.Close();
@@ -209,16 +212,16 @@ namespace mRemoteNG.Tools
private static IPAddress[] IpAddressArrayFromRange(IPAddress ipAddress1, IPAddress ipAddress2)
{
IPAddress startIpAddress = IpAddressMin(ipAddress1, ipAddress2);
IPAddress endIpAddress = IpAddressMax(ipAddress1, ipAddress2);
var startIpAddress = IpAddressMin(ipAddress1, ipAddress2);
var endIpAddress = IpAddressMax(ipAddress1, ipAddress2);
int startAddress = IpAddressToInt32(startIpAddress);
int endAddress = IpAddressToInt32(endIpAddress);
int addressCount = endAddress - startAddress;
var startAddress = IpAddressToInt32(startIpAddress);
var endAddress = IpAddressToInt32(endIpAddress);
var addressCount = endAddress - startAddress;
IPAddress[] addressArray = new IPAddress[addressCount + 1];
int index = 0;
for (int address = startAddress; address <= endAddress; address++)
var addressArray = new IPAddress[addressCount + 1];
var index = 0;
for (var address = startAddress; address <= endAddress; address++)
{
addressArray[index] = IpAddressFromInt32(address);
index++;
@@ -229,26 +232,14 @@ namespace mRemoteNG.Tools
private static IPAddress IpAddressMin(IPAddress ipAddress1, IPAddress ipAddress2)
{
if (IpAddressCompare(ipAddress1, ipAddress2) < 0) // ipAddress1 < ipAddress2
{
return ipAddress1;
}
else
{
return ipAddress2;
}
// ipAddress1 < ipAddress2
return IpAddressCompare(ipAddress1, ipAddress2) < 0 ? ipAddress1 : ipAddress2;
}
private static IPAddress IpAddressMax(IPAddress ipAddress1, IPAddress ipAddress2)
{
if (IpAddressCompare(ipAddress1, ipAddress2) > 0) // ipAddress1 > ipAddress2
{
return ipAddress1;
}
else
{
return ipAddress2;
}
// ipAddress1 > ipAddress2
return IpAddressCompare(ipAddress1, ipAddress2) > 0 ? ipAddress1 : ipAddress2;
}
private static int IpAddressCompare(IPAddress ipAddress1, IPAddress ipAddress2)
@@ -260,10 +251,10 @@ namespace mRemoteNG.Tools
{
if (ipAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
{
throw (new ArgumentException("ipAddress"));
throw new ArgumentException("ipAddress");
}
byte[] addressBytes = ipAddress.GetAddressBytes(); // in network order (big-endian)
var addressBytes = ipAddress.GetAddressBytes(); // in network order (big-endian)
if (BitConverter.IsLittleEndian)
{
Array.Reverse(addressBytes); // to host order (little-endian)
@@ -275,7 +266,7 @@ namespace mRemoteNG.Tools
private static IPAddress IpAddressFromInt32(int ipAddress)
{
byte[] addressBytes = BitConverter.GetBytes(ipAddress); // in host order
var addressBytes = BitConverter.GetBytes(ipAddress); // in host order
if (BitConverter.IsLittleEndian)
{
Array.Reverse(addressBytes); // to network order (big-endian)

View File

@@ -1,54 +1,92 @@
using System;
using System.Drawing;
using mRemoteNG.App;
using Microsoft.Win32.SafeHandles;
// ReSharper disable MemberCanBeMadeStatic.Global
namespace mRemoteNG.Tools
{
public class SystemMenu
{
public sealed class SystemMenu : SafeHandleZeroOrMinusOneIsInvalid, IDisposable
{
[Flags]
public enum Flags
{
MF_STRING = App.NativeMethods.MF_STRING,
MF_SEPARATOR = App.NativeMethods.MF_SEPARATOR,
MF_BYCOMMAND = App.NativeMethods.MF_BYCOMMAND,
MF_BYPOSITION = App.NativeMethods.MF_BYPOSITION,
MF_POPUP = App.NativeMethods.MF_POPUP,
WM_SYSCOMMAND = App.NativeMethods.WM_SYSCOMMAND
MF_STRING = NativeMethods.MF_STRING,
MF_SEPARATOR = NativeMethods.MF_SEPARATOR,
MF_BYCOMMAND = NativeMethods.MF_BYCOMMAND,
MF_BYPOSITION = NativeMethods.MF_BYPOSITION,
MF_POPUP = NativeMethods.MF_POPUP,
WM_SYSCOMMAND = NativeMethods.WM_SYSCOMMAND
}
public IntPtr SystemMenuHandle;
public IntPtr FormHandle;
public SystemMenu(IntPtr Handle)
private bool disposed;
internal IntPtr SystemMenuHandle;
private readonly IntPtr FormHandle;
public SystemMenu(IntPtr Handle) :base(true)
{
FormHandle = Handle;
SystemMenuHandle = App.NativeMethods.GetSystemMenu(FormHandle, false);
}
SystemMenuHandle = NativeMethods.GetSystemMenu(FormHandle, false);
SetHandle(SystemMenuHandle);
}
public void Reset()
{
SystemMenuHandle = App.NativeMethods.GetSystemMenu(FormHandle, true);
SystemMenuHandle = NativeMethods.GetSystemMenu(FormHandle, true);
}
public void AppendMenuItem(IntPtr ParentMenu, Flags Flags, IntPtr ID, string Text)
{
App.NativeMethods.AppendMenu(ParentMenu, (int)Flags, ID, Text);
NativeMethods.AppendMenu(ParentMenu, (int)Flags, ID, Text);
}
public IntPtr CreatePopupMenuItem()
{
return App.NativeMethods.CreatePopupMenu();
return NativeMethods.CreatePopupMenu();
}
public bool InsertMenuItem(IntPtr SysMenu, int Position, Flags Flags, IntPtr SubMenu, string Text)
{
return App.NativeMethods.InsertMenu(SysMenu, Position, (int)Flags, SubMenu, Text);
return NativeMethods.InsertMenu(SysMenu, Position, (int)Flags, SubMenu, Text);
}
public IntPtr SetBitmap(IntPtr Menu, int Position, Flags Flags, Bitmap Bitmap)
{
return new IntPtr(Convert.ToInt32(App.NativeMethods.SetMenuItemBitmaps(Menu, Position, (int)Flags, Bitmap.GetHbitmap(), Bitmap.GetHbitmap())));
return new IntPtr(Convert.ToInt32(NativeMethods.SetMenuItemBitmaps(Menu, Position, (int)Flags, Bitmap.GetHbitmap(), Bitmap.GetHbitmap())));
}
}
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(SystemMenuHandle);
}
/* If we don't have the finalizer, then we get this warning: https://msdn.microsoft.com/library/ms182329.aspx (CA2216: Disposable types should declare finalizer)
* If we DO have the finalizer, then we get this warning: https://msdn.microsoft.com/library/ms244737.aspx (CA1063: Implement IDisposable correctly)
*
* Since the handle is likely going to be in use for the entierty of the process, the finalizer isn't very important since when we're calling it
* the process is likely exiting. Leaks would be moot once it exits. CA2216 is the lesser of 2 evils as far as I can tell. Suppress.
~SystemMenu()
{
Dispose(false);
}
*/
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer")]
public new void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
if (disposed) return;
if (!disposing) return;
ReleaseHandle();
disposed = true;
}
}
}

View File

@@ -63,11 +63,6 @@ namespace mRemoteNG.Tree
connectionInfo?.RemoveParent();
}
public void CloneNode(ConnectionInfo connectionInfo)
{
connectionInfo.Clone();
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void RaiseCollectionChangedEvent(object sender, NotifyCollectionChangedEventArgs args)
{

View File

@@ -717,7 +717,11 @@ namespace mRemoteNG.UI.Controls
private void OnImportFileClicked(object sender, EventArgs e)
{
var selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo ?? _connectionTree.SelectedNode.Parent;
ContainerInfo selectedNodeAsContainer;
if (_connectionTree.SelectedNode == null)
selectedNodeAsContainer = Runtime.ConnectionTreeModel.RootNodes.First();
else
selectedNodeAsContainer = _connectionTree.SelectedNode as ContainerInfo ?? _connectionTree.SelectedNode.Parent;
Import.ImportFromFile(selectedNodeAsContainer);
}

View File

@@ -15,11 +15,12 @@ using mRemoteNG.Tree.Root;
namespace mRemoteNG.UI.Controls
{
public partial class ConnectionTree : TreeListView, IConnectionTree
public partial class ConnectionTree : TreeListView, IConnectionTree
{
private ConnectionTreeModel _connectionTreeModel;
private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler();
private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance;
private bool _allowEdit;
public ConnectionInfo SelectedNode => (ConnectionInfo) SelectedObject;
@@ -90,23 +91,49 @@ namespace mRemoteNG.UI.Controls
Collapsed += (sender, args) =>
{
var container = args.Model as ContainerInfo;
if (container != null)
container.IsExpanded = false;
};
if (container == null) return;
container.IsExpanded = false;
AutoResizeColumn(Columns[0]);
};
Expanded += (sender, args) =>
{
var container = args.Model as ContainerInfo;
if (container != null)
container.IsExpanded = true;
};
if (container == null) return;
container.IsExpanded = true;
AutoResizeColumn(Columns[0]);
};
SelectionChanged += tvConnections_AfterSelect;
MouseDoubleClick += OnMouse_DoubleClick;
MouseClick += OnMouse_SingleClick;
CellToolTipShowing += tvConnections_CellToolTipShowing;
ModelCanDrop += _dragAndDropHandler.HandleEvent_ModelCanDrop;
ModelDropped += _dragAndDropHandler.HandleEvent_ModelDropped;
BeforeLabelEdit += HandleCheckForValidEdit;
}
/// <summary>
/// Resizes the given column to ensure that all content is shown
/// </summary>
private void AutoResizeColumn(ColumnHeader column)
{
var longestIndentationAndTextWidth = int.MinValue;
var horizontalScrollOffset = LowLevelScrollPosition.X;
const int padding = 10;
for (var i = 0; i < Items.Count; i++)
{
var rowIndentation = Items[i].Position.X;
var rowTextWidth = TextRenderer.MeasureText(Items[i].Text, Font).Width;
longestIndentationAndTextWidth = Math.Max(rowIndentation + rowTextWidth, longestIndentationAndTextWidth);
}
column.Width = longestIndentationAndTextWidth +
SmallImageSize.Width +
horizontalScrollOffset +
padding;
}
private void PopulateTreeView()
{
UnregisterModelUpdateHandlers();
@@ -114,7 +141,8 @@ namespace mRemoteNG.UI.Controls
RegisterModelUpdateHandlers();
NodeSearcher = new NodeSearcher(ConnectionTreeModel);
ExecutePostSetupActions();
}
AutoResizeColumn(Columns[0]);
}
private void RegisterModelUpdateHandlers()
{
@@ -137,13 +165,17 @@ namespace mRemoteNG.UI.Controls
private void HandleCollectionPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
//TODO for some reason property changed events are getting triggered twice for each changed property. should be just once. cant find source of duplication
// for some reason property changed events are getting triggered twice for each changed property. should be just once. cant find source of duplication
// Removed "TO DO" from above comment. Per #142 it apperas that this no longer occurs with ObjectListView 2.9.1
var property = propertyChangedEventArgs.PropertyName;
if (property != "Name" && property != "OpenConnections") return;
var senderAsConnectionInfo = sender as ConnectionInfo;
if (senderAsConnectionInfo != null)
RefreshObject(senderAsConnectionInfo);
}
if (senderAsConnectionInfo == null)
return;
RefreshObject(senderAsConnectionInfo);
AutoResizeColumn(Columns[0]);
}
private void ExecutePostSetupActions()
{
@@ -201,11 +233,12 @@ namespace mRemoteNG.UI.Controls
private void AddNode(ConnectionInfo newNode)
{
if (SelectedNode == null) return;
// use root node if no node is selected
ConnectionInfo parentNode = SelectedNode ?? GetRootConnectionNode();
DefaultConnectionInfo.Instance.SaveTo(newNode);
DefaultConnectionInheritance.Instance.SaveTo(newNode.Inheritance);
var selectedContainer = SelectedNode as ContainerInfo;
var parent = selectedContainer ?? SelectedNode?.Parent;
var selectedContainer = parentNode as ContainerInfo;
var parent = selectedContainer ?? parentNode.Parent;
newNode.SetParent(parent);
Expand(parent);
SelectObject(newNode, true);
@@ -215,16 +248,31 @@ namespace mRemoteNG.UI.Controls
public void DuplicateSelectedNode()
{
var newNode = SelectedNode.Clone();
SelectedNode.Parent.AddChildBelow(newNode, SelectedNode);
newNode.Parent.SetChildBelow(newNode, SelectedNode);
Runtime.SaveConnectionsAsync();
}
public void RenameSelectedNode()
{
_allowEdit = true;
SelectedItem.BeginEdit();
Runtime.SaveConnectionsAsync();
}
public void HandleCheckForValidEdit(object sender, LabelEditEventArgs e)
{
if (!(sender is ConnectionTree)) return;
if (_allowEdit)
{
_allowEdit = false;
}
else
{
e.CancelEdit = true;
}
}
public void DeleteSelectedNode()
{
if (SelectedNode is RootNodeInfo || SelectedNode is PuttySessionInfo) return;
@@ -236,7 +284,8 @@ namespace mRemoteNG.UI.Controls
private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
{
RefreshObject(sender);
}
AutoResizeColumn(Columns[0]);
}
private void tvConnections_AfterSelect(object sender, EventArgs e)
{
@@ -255,7 +304,7 @@ namespace mRemoteNG.UI.Controls
if (mouseEventArgs.Clicks < 2) return;
OLVColumn column;
var listItem = GetItemAt(mouseEventArgs.X, mouseEventArgs.Y, out column);
var clickedNode = listItem.RowObject as ConnectionInfo;
var clickedNode = listItem?.RowObject as ConnectionInfo;
if (clickedNode == null) return;
DoubleClickHandler.Execute(clickedNode);
}

View File

@@ -9,8 +9,7 @@ namespace mRemoteNG.UI.Controls
public NameColumn(ImageGetterDelegate imageGetterDelegate)
{
AspectName = "Name";
FillsFreeSpace = true;
IsButton = true;
FillsFreeSpace = false;
AspectGetter = item => ((ConnectionInfo) item).Name;
ImageGetter = imageGetterDelegate;
}

View File

@@ -78,10 +78,10 @@ namespace mRemoteNG.UI.Forms.OptionsPages
radCredentialsCustom.Checked = true;
}
txtCredentialsUsername.Text = Convert.ToString(Settings.Default.DefaultUsername);
txtCredentialsUsername.Text = Settings.Default.DefaultUsername;
var cryptographyProvider = new LegacyRijndaelCryptographyProvider();
txtCredentialsPassword.Text = cryptographyProvider.Decrypt(Convert.ToString(Settings.Default.DefaultPassword), Runtime.EncryptionKey);
txtCredentialsDomain.Text = Convert.ToString(Settings.Default.DefaultDomain);
txtCredentialsPassword.Text = cryptographyProvider.Decrypt(Settings.Default.DefaultPassword, Runtime.EncryptionKey);
txtCredentialsDomain.Text = Settings.Default.DefaultDomain;
if (Settings.Default.ConfirmCloseConnection == (int) ConfirmCloseEnum.Never)
{

View File

@@ -46,9 +46,6 @@ namespace mRemoteNG.UI.Forms
private ConnectionTreeWindow ConnectionTreeWindow { get; set; }
private readonly IConnectionInitiator _connectionInitiator = new ConnectionInitiator();
private frmMain()
{
_showFullPathInTitle = Settings.Default.ShowCompleteConsPathInTitle;
@@ -190,8 +187,9 @@ namespace mRemoteNG.UI.Forms
// Create gui config load and save objects
var settingsLoader = new SettingsLoader(this);
settingsLoader.LoadSettings();
ApplyLanguage();
LoadDefaultConnectionInfo();
ApplyLanguage();
PopulateQuickConnectProtocolMenu();
ThemeManager.ThemeChanged += ApplyThemes;
ApplyThemes();
@@ -224,6 +222,12 @@ namespace mRemoteNG.UI.Forms
ConnectionTreeWindow = Windows.TreeForm;
}
private void LoadDefaultConnectionInfo()
{
DefaultConnectionInfo.Instance.LoadFrom(Settings.Default, a => "ConDefault" + a);
DefaultConnectionInheritance.Instance.LoadFrom(Settings.Default, a => "InhDefault" + a);
}
private void ApplyLanguage()
{
mMenFile.Text = Language.strMenuFile;
@@ -453,13 +457,14 @@ namespace mRemoteNG.UI.Forms
var extA = (ExternalTool)((ToolStripButton)sender).Tag;
var selectedTreeNode = Windows.TreeForm.SelectedNode;
if (selectedTreeNode.GetTreeNodeType() == TreeNodeType.Connection | selectedTreeNode.GetTreeNodeType() == TreeNodeType.PuttySession)
if (selectedTreeNode != null && selectedTreeNode.GetTreeNodeType() == TreeNodeType.Connection | selectedTreeNode.GetTreeNodeType() == TreeNodeType.PuttySession)
{
extA.Start(selectedTreeNode);
}
else
{
extA.Start();
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "No connection was selected, external tool may return errors.", true);
extA.Start();
}
}
@@ -1071,30 +1076,37 @@ namespace mRemoteNG.UI.Forms
var control = FromChildHandle(NativeMethods.WindowFromPoint(MousePosition));
if (control != null)
{
// Let TreeViews and ComboBoxes get focus but don't simulate a mouse event
if (control is TreeView || control is ComboBox)
{ }
else
{
if (control.CanSelect || control is MenuStrip || control is ToolStrip || control is Crownwood.Magic.Controls.TabControl || control is Crownwood.Magic.Controls.InertButton)
{
// Simulate a mouse event since one wasn't generated by Windows
var clientMousePosition = control.PointToClient(MousePosition);
var temp_wLow = clientMousePosition.X;
var temp_wHigh = clientMousePosition.Y;
NativeMethods.SendMessage(control.Handle, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, (IntPtr)NativeMethods.MAKELPARAM(ref temp_wLow, ref temp_wHigh));
clientMousePosition.X = temp_wLow;
clientMousePosition.Y = temp_wHigh;
control.Focus();
}
}
}
// This handles activations from clicks that did not start a size/move operation
ActivateConnection();
}
break;
case NativeMethods.WM_WINDOWPOSCHANGED:
// Let TreeViews get focus but don't simulate a mouse event
if (control is TreeView ||
control is ComboBox ||
control is TextBox)
{
control.Focus();
}
else if (control.CanSelect ||
control is MenuStrip ||
control is ToolStrip ||
control is Crownwood.Magic.Controls.TabControl ||
control is Crownwood.Magic.Controls.InertButton)
{
// Simulate a mouse event since one wasn't generated by Windows
var clientMousePosition = control.PointToClient(MousePosition);
var temp_wLow = clientMousePosition.X;
var temp_wHigh = clientMousePosition.Y;
NativeMethods.SendMessage(control.Handle, NativeMethods.WM_LBUTTONDOWN, (IntPtr)NativeMethods.MK_LBUTTON, (IntPtr)NativeMethods.MAKELPARAM(ref temp_wLow, ref temp_wHigh));
clientMousePosition.X = temp_wLow;
clientMousePosition.Y = temp_wHigh;
control.Focus();
}
else
{
// This handles activations from clicks that did not start a size/move operation
ActivateConnection();
}
}
}
break;
case NativeMethods.WM_WINDOWPOSCHANGED:
// Ignore this message if the window wasn't activated
var windowPos = (NativeMethods.WINDOWPOS)Marshal.PtrToStructure(m.LParam, typeof(NativeMethods.WINDOWPOS));
if ((windowPos.flags & NativeMethods.SWP_NOACTIVATE) != 0)

View File

@@ -33,6 +33,7 @@ namespace mRemoteNG.UI.Window
this.lblEdition = new System.Windows.Forms.Label();
this.pbLogo = new System.Windows.Forms.PictureBox();
this.pnlBottom = new System.Windows.Forms.Panel();
this.verText = new System.Windows.Forms.TextBox();
this.lblCredits = new System.Windows.Forms.Label();
this.txtCredits = new System.Windows.Forms.TextBox();
this.txtChangeLog = new System.Windows.Forms.TextBox();
@@ -41,7 +42,6 @@ namespace mRemoteNG.UI.Window
this.lblChangeLog = new System.Windows.Forms.Label();
this.lblLicense = new System.Windows.Forms.Label();
this.lblCopyright = new System.Windows.Forms.Label();
this.verText = new System.Windows.Forms.TextBox();
this.pnlTop.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pbLogo)).BeginInit();
this.pnlBottom.SuspendLayout();
@@ -105,6 +105,18 @@ namespace mRemoteNG.UI.Window
this.pnlBottom.Size = new System.Drawing.Size(1121, 559);
this.pnlBottom.TabIndex = 1;
//
// verText
//
this.verText.BackColor = System.Drawing.SystemColors.Control;
this.verText.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.verText.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.verText.Location = new System.Drawing.Point(69, 51);
this.verText.Name = "verText";
this.verText.Size = new System.Drawing.Size(147, 20);
this.verText.TabIndex = 12;
this.verText.TabStop = false;
this.verText.Text = "w.x.y.z";
//
// lblCredits
//
this.lblCredits.AutoSize = true;
@@ -119,6 +131,8 @@ namespace mRemoteNG.UI.Window
//
// txtCredits
//
this.txtCredits.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.txtCredits.BackColor = System.Drawing.SystemColors.Control;
this.txtCredits.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.txtCredits.Cursor = System.Windows.Forms.Cursors.Default;
@@ -136,6 +150,9 @@ namespace mRemoteNG.UI.Window
//
// txtChangeLog
//
this.txtChangeLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtChangeLog.BackColor = System.Drawing.SystemColors.Control;
this.txtChangeLog.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.txtChangeLog.Cursor = System.Windows.Forms.Cursors.Default;
@@ -211,18 +228,6 @@ namespace mRemoteNG.UI.Window
this.lblCopyright.Text = "Copyright";
this.lblCopyright.UseCompatibleTextRendering = true;
//
// verText
//
this.verText.BackColor = System.Drawing.SystemColors.Control;
this.verText.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.verText.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.verText.Location = new System.Drawing.Point(69, 51);
this.verText.Name = "verText";
this.verText.Size = new System.Drawing.Size(147, 20);
this.verText.TabIndex = 12;
this.verText.TabStop = false;
this.verText.Text = "w.x.y.z";
//
// AboutWindow
//
this.BackColor = System.Drawing.SystemColors.Control;
@@ -251,7 +256,8 @@ namespace mRemoteNG.UI.Window
public AboutWindow(DockContent Panel)
{
WindowType = WindowType.About;
DockPnl = Panel;
DockPnl = Panel;
DockPnl = new DockContent();
InitializeComponent();
Runtime.FontOverride(this);
}

View File

@@ -1,5 +1,7 @@
using mRemoteNG.Tree;
namespace mRemoteNG.UI.Window
{
public partial class ConnectionTreeWindow : BaseWindow
@@ -19,6 +21,9 @@ namespace mRemoteNG.UI.Window
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
mRemoteNG.Tree.TreeNodeCompositeClickHandler treeNodeCompositeClickHandler1 = new mRemoteNG.Tree.TreeNodeCompositeClickHandler();
mRemoteNG.Tree.AlwaysConfirmYes alwaysConfirmYes1 = new mRemoteNG.Tree.AlwaysConfirmYes();
mRemoteNG.Tree.TreeNodeCompositeClickHandler treeNodeCompositeClickHandler2 = new mRemoteNG.Tree.TreeNodeCompositeClickHandler();
this.olvConnections = new mRemoteNG.UI.Controls.ConnectionTree();
this.pnlConnections = new System.Windows.Forms.Panel();
this.PictureBox1 = new System.Windows.Forms.PictureBox();
@@ -44,22 +49,31 @@ namespace mRemoteNG.UI.Window
| System.Windows.Forms.AnchorStyles.Right)));
this.olvConnections.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.olvConnections.CellEditUseWholeCell = false;
this.olvConnections.ConnectionTreeModel = new ConnectionTreeModel();
this.olvConnections.Cursor = System.Windows.Forms.Cursors.Default;
treeNodeCompositeClickHandler1.ClickHandlers = new mRemoteNG.Tree.ITreeNodeClickHandler[0];
this.olvConnections.DoubleClickHandler = treeNodeCompositeClickHandler1;
this.olvConnections.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
this.olvConnections.HideSelection = false;
this.olvConnections.IsSimpleDragSource = true;
this.olvConnections.IsSimpleDropSink = true;
this.olvConnections.LabelEdit = true;
this.olvConnections.Location = new System.Drawing.Point(0, 0);
this.olvConnections.MultiSelect = false;
this.olvConnections.Name = "olvConnections";
this.olvConnections.NodeDeletionConfirmer = alwaysConfirmYes1;
this.olvConnections.PostSetupActions = new mRemoteNG.UI.Controls.IConnectionTreeDelegate[0];
this.olvConnections.SelectedBackColor = System.Drawing.SystemColors.Highlight;
this.olvConnections.SelectedForeColor = System.Drawing.SystemColors.HighlightText;
this.olvConnections.ShowGroups = false;
treeNodeCompositeClickHandler2.ClickHandlers = new mRemoteNG.Tree.ITreeNodeClickHandler[0];
this.olvConnections.SingleClickHandler = treeNodeCompositeClickHandler2;
this.olvConnections.Size = new System.Drawing.Size(192, 410);
this.olvConnections.TabIndex = 20;
this.olvConnections.UnfocusedSelectedBackColor = System.Drawing.SystemColors.Highlight;
this.olvConnections.UnfocusedSelectedForeColor = System.Drawing.SystemColors.HighlightText;
this.olvConnections.UseCompatibleStateImageBehavior = false;
this.olvConnections.UseOverlays = false;
this.olvConnections.View = System.Windows.Forms.View.Details;
this.olvConnections.VirtualMode = true;
//

View File

@@ -123,10 +123,9 @@ namespace mRemoteNG.UI.Window
private void btnImport_Click(object sender, EventArgs e)
{
ProtocolType protocol = (ProtocolType)StringToEnum(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem));
var protocol = (ProtocolType)StringToEnum(typeof(ProtocolType), Convert.ToString(cbProtocol.SelectedItem));
importSelectedHosts(protocol);
DialogResult = DialogResult.OK;
Close();
}
#endregion
@@ -168,8 +167,8 @@ namespace mRemoteNG.UI.Window
SwitchButtonText();
lvHosts.Items.Clear();
System.Net.IPAddress ipAddressStart = System.Net.IPAddress.Parse(ipStart.Text);
System.Net.IPAddress ipAddressEnd = System.Net.IPAddress.Parse(ipEnd.Text);
var ipAddressStart = System.Net.IPAddress.Parse(ipStart.Text);
var ipAddressEnd = System.Net.IPAddress.Parse(ipEnd.Text);
_portScanner = new PortScanner(ipAddressStart, ipAddressEnd, (int) portStart.Value, (int) portEnd.Value);
@@ -198,9 +197,14 @@ namespace mRemoteNG.UI.Window
prgBar.Maximum = 100;
prgBar.Value = 0;
/* If there are still hosts timing out, we might call PortScannerHostScannedDelegate after the import which will throw exceptions...
* Disable the import button until after the scan is complete
*/
btnImport.Enabled = !_scanning;
}
private static void PortScanner_BeginHostScan(string host)
private static void PortScanner_BeginHostScan(string host)
{
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Scanning " + host, true);
}
@@ -210,13 +214,13 @@ namespace mRemoteNG.UI.Window
{
if (InvokeRequired)
{
Invoke(new PortScannerHostScannedDelegate(PortScanner_HostScanned), new object[] {host, scannedCount, totalCount});
Invoke(new PortScannerHostScannedDelegate(PortScanner_HostScanned), host, scannedCount, totalCount);
return;
}
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "Host scanned " + host.HostIp, true);
ListViewItem listViewItem = host.ToListViewItem();
var listViewItem = host.ToListViewItem();
if (listViewItem != null)
{
lvHosts.Items.Add(listViewItem);
@@ -232,7 +236,7 @@ namespace mRemoteNG.UI.Window
{
if (InvokeRequired)
{
Invoke(new PortScannerScanComplete(PortScanner_ScanComplete), new object[] {hosts});
Invoke(new PortScannerScanComplete(PortScanner_ScanComplete), hosts);
return;
}
@@ -245,6 +249,13 @@ namespace mRemoteNG.UI.Window
private void importSelectedHosts(ProtocolType protocol)
{
if (lvHosts.SelectedItems.Count < 1)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "importSelectedHosts: Could not import host(s) from port scan context menu. No hosts selected.");
return;
}
var hosts = new List<ScanHost>();
foreach (ListViewItem item in lvHosts.SelectedItems)
{
@@ -257,11 +268,21 @@ namespace mRemoteNG.UI.Window
if (hosts.Count < 1)
{
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "Could not import host(s) from port scan context menu");
Runtime.MessageCollector.AddMessage(MessageClass.WarningMsg, "importSelectedHosts: Could not import host(s) from port scan context menu", true);
return;
}
var selectedTreeNodeAsContainer = Windows.TreeForm.SelectedNode as ContainerInfo ?? Windows.TreeForm.SelectedNode.Parent;
ContainerInfo selectedTreeNodeAsContainer;
if (Windows.TreeForm.SelectedNode == null)
{
selectedTreeNodeAsContainer = Windows.TreeForm.ConnectionTree.GetRootConnectionNode();
Runtime.MessageCollector.AddMessage(MessageClass.InformationMsg, "importSelectedHosts: No node selected. Using Root Node.", true);
}
else
{
selectedTreeNodeAsContainer = Windows.TreeForm.SelectedNode as ContainerInfo ?? Windows.TreeForm.SelectedNode.Parent;
}
Import.ImportFromPortScan(hosts, protocol, selectedTreeNodeAsContainer);
}

View File

@@ -1248,44 +1248,19 @@
<Reference Include="mscorlib" />
</ItemGroup>
<PropertyGroup>
<PostBuildEvent>powershell -noprofile -command "sleep 2"
call "$(DevEnvDir)..\tools\vsvars32.bat"
set /p buildenv=&lt;buildenv.tmp
echo Copy PUTTYNG to correct directory
copy /Y "$(SolutionDir)mRemoteV1\Resources\PuTTYNG.exe" .\
echo Move Help files to correct directory
IF EXIST Help (
del /s /q Help &gt;NUL
rmdir /s /q Help &gt;NUL
)
move /Y Resources\Help .\
<PostBuildEvent>:: When passing paths to powershell scripts, check if the path ends with a backslash "\"
:: If it does, then the backslash may be interpreted as an escape character. Add another backslash to cancel the first one.
powershell -noprofile -command "sleep 2"
rmdir /s /q Resources &gt;NUL
set /p buildenv=&lt;buildenv.tmp
set solutionDir=$(SolutionDir)\
set targetDir=%25cd%25
set psScriptsDir=$(SolutionDir)Tools
set certPath=$(CertPath)
set certPassword=$(CertPassword)
echo Set LargeAddressAware on binary
editbin /largeaddressaware mRemoteNG.exe
IF EXIST C:\mRemoteNG_code_signing_cert.pfx (
echo Signing binaries
IF %25buildenv: Portable=%25==Release (
powershell "&amp;""$(SolutionDir)Tools\signfiles.ps1""" '%25cd%25'
)
)
IF %25buildenv: Portable=%25==Release (
echo Remove unnecessary files from Release versions
rmdir /s /q app.publish
del /q *.pdb *.publish *.xml *.backup *.log *vshost* *.tmp
)
IF %25buildenv: =%25==ReleasePortable (
echo Package ZIP Release Portable
"$(SolutionDir)Tools\build-relport.cmd"
)</PostBuildEvent>
:: Call the post build powershell script
powershell.exe -ExecutionPolicy Bypass -File "%25psScriptsDir%25\postbuild_mremotev1.ps1" -SolutionDir "%25solutionDir%25" -TargetDir "%25targetDir%25" -TargetFileName "mRemoteNG.exe" -ConfigurationName "%25buildenv%25" -CertificatePath "%25certPath%25" -CertificatePassword "%25certPassword%25" -ExcludeFromSigning "PuTTYNG.exe"</PostBuildEvent>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>

View File

@@ -1,199 +0,0 @@
================================================================================================
1.10.0 Release
================================================================================================
Substitutes will now automatically return an empty `IQueryable<T>` for
members that return that type. Tests previously relying on a
substitute `IQueryable<T>` will no longer work properly.
Reason:
Code that uses an `IQueryable<T>` can now run using the auto-subbed
value without causing null pointer exceptions (see issue #67).
Fix:
Avoid mocking `IQueryable<T>` where possible -- configure members
to return a real `IQueryable<T>` instead.
If a substitute is required, explicitly configure the call to return
a substitute:
sub.MyQueryable().Returns(Substitute.For<IQueryable<int>>());
================================================================================================
1.9.1 Release
================================================================================================
Substitutes set up to throw exception for methods with return type Task<T>
cause compilation to fail due to the call being ambiguous (CS0121).
"The call is ambiguous between the following methods or properties:
.Returns<Task<T>> and .Returns<T>"
Reason:
To make it easier to stub async methods. See issue #189.
Fix:
Specify generic type argument explicitly. If Method() returns string:
Old: sub.Method().Returns(x => { throw new Exception() });
New: sub.Method().Returns<string>(x => { throw new Exception() });
================================================================================================
1.8.0 Release
================================================================================================
Incorrect use of argument matchers outside of a member call, particularly within a
Returns(), will now throw an exception (instead of causing unexpected behaviour
in other tests: see https://github.com/nsubstitute/NSubstitute/issues/149).
Reason:
Prevent accidental incorrect use from causing hard-to-find errors in unrelated tests.
Fix:
Do not use argument matchers in Returns() or outside of where an argument is normally used.
Correct use: sub.Method(Arg.Any<string>()).Returns("hi")
Incorrect use: sub.Method().Returns(Arg.Any<string>())
================================================================================================
1.7.0 Release
================================================================================================
Auto-substitute for pure virtual classes with at least one public static method, which
means some methods and properties on substitutes that used to return null by default will now
return a new substitute of that type.
Reason:
Keep consistency with the behaviour of other pure virtual classes.
Fix:
Explicitly return null from methods and property getters when required for a test.
e.g. sub.Method().Returns(x => null);
------------------------------------------------------------------------------------------------
Moved `Received.InOrder` feature from `NSubstitute.Experimental` to main `NSubstitute` namespace.
Obsoleted original `NSubstitute.Experimental.Received`.
This can result in ambiguous reference compiler errors and obsolete member compiler earnings.
Reason:
Promoted experimental Received feature to core library.
Fix:
Import `NSubstitute` namespace instead of `NSubstitute.Experimental`.
(If `NSubstitute` is already imported just delete the `using NSubstitute.Experimental;` line from your fixtures.)
================================================================================================
1.5.0 Release
================================================================================================
The base object methods (Equals, GetHashCode and ToString) for substitute objects of classes that
extend those methods now return the result of calling the actual implementation of those methods
rather than the default value for the return type. This means that places where you relied on
.Equals returning false, .ToString returning null and .GetHashCode returning 0 because the actual
methods weren't called will now call the actual implementation.
Reason:
Substitute objects of classes that overrode those methods that were used as parameters for
setting up return values or checking received calls weren't able to be directly used within the
call, e.g. instead of:
someObject.SomeCall(aSubstitute).Returns(1);
You previously needed to have:
someObject.SomeCall(Arg.Is<TypeBeingSubstituted>(a => a == aSubstitute)).Returns(1);
However, now you can use the former, which is much more terse and consistent with the way other
Returns or Received calls work.
This means that substitute objects will now always work like .NET objects rather than being
inconsistent when the class being substituted overrode any of those base object methods.
Fix:
There is no workaround to change the behaviour of .Equals, .GetHashCode or .ToString. If you have
a use case to change the behaviour of these methods please lodge an issue at the NSubstitute
Github site.
------------------------------------------------------------------------------------------------
In rare cases the new `Returns()` and `ReturnsForAnyArgs()` overloads can cause compilation to fail due to the call being ambiguous (CS0121).
Reason:
The new overloads allow a sequence of callbacks to be used for return values. A common example is return several values, then throwing an exception.
Fix:
Remove the ambiguity by explicitly casting the arguments types or by using lambda syntax.
e.g. sub.Call().Returns(x => null, x => null);
================================================================================================
1.4.0 Release
================================================================================================
Auto-substitute from substitutes of `Func` delegates (following the same rules as auto-subbing
for methods and properties). So the delegate returned from `Substitute.For<Func<IFoo>>()` will
return a substitute of `IFoo`. This means some substitutes for delegates that used to return
null will now return a new substitute.
Reason:
Reduced setup when substituting for `Func` delegates, and consistency with behaviour for
properties and methods.
Fix:
Explicitly return null from substitute delegates when required for a test.
e.g. subFunc().Returns(x => null);
================================================================================================
1.2.0 Release
================================================================================================
Auto-substitute for pure virtual classes (in addition to interfaces and delegate types), which
means some methods and properties on substitutes that used to return null by default will now
return a new substitute of that type.
Reason:
Cut down the code required to configure substitute members that return interface-like types
(e.g. ASP.NET web abstractions like HttpContextBase) which are safe to create and proxy.
Safe classes are those with all their public methods and properties defined as virtual or
abstract, and containing a default, parameterless constructor defined as public or protected.
Fix:
Explicitly return null from methods and property getters when required for a test.
e.g. sub.Method().Returns(x => null);
================================================================================================
0.9.5 Release
================================================================================================
Raise.Event<TEventArgs>(...) methods renamed to Raise.EventWith<TEventArgs()
Reason:
The Raise.Event<TEventArgs>() signature would often conflict with the
Raise.Event<THandler>() method which is used to raise all types of events.
Raise.Event<THandler>() will now always work for any event type, while
Raise.EventWith<TEventArgs>() can be used as a shortcut to raise
EventHandler-style events with a particular argument.
Fix:
Replace Raise.Event<TEventArgs>() calls with equivalent Raise.EventWith<TEventArgs>() call.
------------------------------------------------------------------------------------------------
Raise.Action() methods removed
Reason:
The Raise.Event<THandler>() method can be used to raise all delegate events, including Actions.
Raise.Action() was removed so there is a consistent way of raising all delegate events.
Fix:
- Replace Raise.Action() calls with Raise.Event<Action>().
- Replace Raise.Action<T>(T arg) calls with Raise.Event<Action<T>>(arg).
- Replace Raise.Action<T1,T2>(T1 x, T2 y) calls with Raise.Event<Action<T1,T2>>(x, y).
================================================================================================
0.9.0 Release
================================================================================================
No breaking changes.

View File

@@ -1,151 +0,0 @@
### 1.10.0 (March 2016)
* [NEW] Callbacks builder for more control over When..Do callbacks. Thanks to bartoszgolek. (#202, #200)
* [NEW] Auto-substitute for IQueryable<T>. Thanks to emragins. (#67)
* [FIX] Fix bug when showing params arguments for value types (#214)
* [FIX] Fix bug when showing params arguments for Received.InOrder calls (#211)
### 1.9.2 (October 2015)
* [UPDATE] Mark Exceptions as [Serializable]. Thanks to David Mann. (#201)
* [FIX] Fix bug with concurrently creating delegate substitutes. Thanks to Alexandr Nikitin. (#205)
### 1.9.1 (October 2015)
* [FIX] Fix bug introduced in 1.9.0 that made checking a call was Received() clear previously stubbed values for that call.
### 1.9.0 (October 2015)
* [NEW] Allow awaiting of async methods with Received()/DidNotReceive(). Thanks to Marcio Rinaldi for this contribution. (#190, #191)
* [NEW] Task-specific Returns methods to make it easier to stub async methods. Thanks to Antony Koch for implementing this, and thanks to Marius Gundersen and Alexandr Nikitin for the suggestion and discussion regarding the change. (#189) (Also thanks to Jake Ginnivan who tried adding this back in #91, but I didn't merge that part of the PR in. Sorry!)
* [NEW] ReturnsForAll<T> extension method. Thanks to Mike Hanson for this contribution. (#198, #196)
### 1.8.2 (May 2015)
* [NEW] Convenience .ReturnsNull() extensions in NSubstitute.ReturnsExtensions. Thanks to Michal Wereda for this contribution. (#181)
* [NEW] CallInfo.ArgAt<T>(int) added to match argument at a given position and cast to the required type. Thanks to @jotabe-net for this contribution. (#175)
* [NEW] Convenience Throws() extensions in NSubstitute.ExceptionExtensions (sub.MyCall().Throws(ex)). Thanks to Michal Wereda for this contribution. Thanks also to Geir Sagberg for helpful suggestions relating to this feature. (#172)
### 1.8.1 (December 2014)
* [FIX] Fix for methods returning multidimensional arrays. Thanks to Alexandr Nikitin. (#170)
### 1.8.0 (November 2014)
* [NEW] Convenience methods for throwing exceptions with When-Do. Thanks to Geir Sagberg for this contribution.
* [FIX] Throw exception when arg matcher used within Returns. (#149)
### 1.7.2 (March 2014)
* [FIX] Basic support for types that return dynamic. Thanks to Alexandr Nikitin. (#75)
* [NEW] Auto-subbing for observables. Thanks to Paul Betts.
### 1.7.1 (January 2014)
* [FIX] Ambiguous arg exception with out/ref parameters. Thanks to Alexandr Nikitin. (#129)
### 1.7.0 (January 2014)
* [NEW] Partial subs (Substitute.ForPartsOf<T>()). Thanks to Alexandr Nikitin for tonnes of hard work on this feature (and for putting up with a vacillating project owner :)).
* [UPDATE] Received.InOrder moved out of Experimental namespace.
* [FIX] Argument matching with optional parameters. Thanks to Peter Wiles. (#111)
* [FIX] Argument matching with out/ref. Thanks to Kevin Bosman. (#111)
* [FIX] The default return value for any call that returns a concrete type that is purely virtual, but also has at least one public static method in it will be a substitute rather than null. Thanks to Robert Moore (@robdmoore) for this contribution. (#118)
### 1.6.1 (June 2013)
* [FIX] Detect and throw on type mismatches in Returns() caused by Returns(ConfigureOtherSub()).
* [FIX] Support raising exceptions that do not implement a serialisation constructor (#110). Thanks to Alexandr Nikitin for this contribution.
### 1.6.0 (April 2013)
* [NEW] .AndDoes() method for chaining a callback after a Returns(). (#98)
* [FIX] Handling calls with params argument of value types, thanks to Eric Winkler.
* [FIX] Can now substitute for interfaces implementing System.Windows.IDataObject, thanks to Johan Appelgren.
* [UPDATE] Improved XML doc comments, thanks to David Gardiner.
### 1.5.0 (January 2013)
* [EXPERIMENTAL] Asserting ordered call sequences
* [FIX] Arg.Invoke with four arguments now passes fourth arg correctly (#88). Thanks to Ville Salonen (@VilleSalonen) for finding and patching this.
* [FIX] Substitute objects now use actual implementation for base object methods (Equals, GetHashCode, ToString). Thanks to Robert Moore (@robdmoore) for this contribution. (#77)
* [NEW] Auto-substitute for Task/Task<T>. Task<T> will use substitute rules that T would use. Thanks to Jake Ginnivan (@JakeGinnivan) for this contribution.
* [NEW] Match derived types for generic calls (#97). Thanks to Iain Ballard for this contribution.
* [NEW] Returns now supports passing multiple callbacks, which makes it easier to combine stubbing multiple return values followed by throwing an exception (#99). Thanks to Alexandr Nikitin for this contribution.
### 1.4.3 (August 2012)
* [FIX] Updated to Castle.Core 3.1.0 to fix an issue proxying generic methods with a struct constraint (#83).
### 1.4.2 (July 2012)
* [FIX] Issue using NET40 build on Mono (due to NET45 build tools incompatibility)
### 1.4.1 (June 2012)
* [FIX] Fix matching Nullable<T> arguments when arg value is null. Thanks to Magnus Olstad Hansen (@maggedotno) for this contribution. (#78)
* [UPDATE] Updated to Castle.Core 3.0.0.
### 1.4.0 (May 2012)
* [NEW] [BREAKING] Auto-substitute for types returned from substitutes of delegates/Funcs (follows same auto-substitute rules as for methods and properties). Thanks to Sauli T<>hk<68>p<EFBFBD><70> for implementing this feature. (#52)
* [NEW] Show details of params arguments when displaying received calls. Thanks to Sauli T<>hk<68>p<EFBFBD><70> for implementing this feature. (#65)
* [FIX] Race condition between checking received calls and building the exception could cause nonsensical exception messages like "Expected 5, actually received 5" when called concurrently. (#64)
### 1.3.0 (Nov 2011)
* [NEW] Support for Received(times) to assert a call was received a certain number of times. Thanks to Abi Bellamkonda for this contribution. (#63)
* [FIX] Improved support for calling substitutes from multiple threads. (#62)
### 1.2.1 (Oct 2011)
* [FIX] Some combinations of Arg.Do and Returns() caused incorrect values to be returned. (#59)
* [UPDATE] WCF ServiceContractAttribute no longer applied to proxies. (#60)
* [FIX] Passing null could cause argument actions to fail. (#61)
* [FIX] Calls to virtual methods from constructors of classes being substituted for are no longer recorded, to prevent non-obvious behaviour when calling Returns() on an auto-substituted value. (#57)
### 1.2.0 (Sep 2011)
* [NEW] Arg.Do() syntax for capturing arguments passed to a method and performing some action with them whenever the method is called.
* [NEW] Arg.Invoke() syntax for invoking callbacks passed as arguments to a method whenever the method is called.
* [NEW] Basic support for setting out/ref parameters.
* [FIX] Property behaviour for indexed properties (Issue #53)
* [UPDATE] [BREAKING] Auto-substitute for pure virtual classes, including common ASP.NET web abstractions. Use .Returns(x=>null) to explicitly return null from these members if required. Thanks to Tatham Oddie for original idea and patch, and Krzysztof Kozmic for suggesting and defining which classes would be safe to automatically proxy.
* [UPDATE] Changed layout of package for eventual support for multiple framework targets.
* [FIX] Failure to match calls with ref arguments using ReceivedWithAnyArgs().
* [FIX] Incorrect ambiguous args exception when supplying value type arg specs for object arguments.
### 1.1.0 (May 2011)
* [UPDATE] Updated to Castle.Core 2.5.3.
* [FIX] Fixed bug when raising a delegate event with a null argument.
* [FIX] CallInfo.Arg<T>() now works more reliably, including for null arguments.
* [FIX] Better exception when accidentally calling substitute extension method with a null reference (e.g. foo.Received().Call() when foo is null)
* [UPDATE] Exceptions thrown in custom argument matchers (Arg.Is<T>(x => ...)) will now silently fail to match the argument, rather than allowing exceptions to bubble up.
* [NEW] Support for test fixtures run in parallel.
### 1.0.0 (Dec 2010)
* [FIX] Using Returns(null) for value types throws, rather than returning default(T).
0.9.5 Release Candidate
* [FIX] Fixed bug when trying to return null from a call to a substitute.
* [FIX] Equals() for class substitutes fixed by not intercepting Object methods Equals(), ToString() and GetHashCode().
* [NEW] Raise.Event<THandler>() methods to raise any type of event, including delegates.
* [BREAKING] Raise.Action() methods removed. Use Raise.Event<THandler>() (e.g. Raise.Event<Action>>()).
* [BREAKING] Renamed Raise.Event<TEventArgs>() methods to Raise.EventWith<TEventArgs>().
* [UPDATE] Arg matchers can be specified using more specific, compatible type (Arg.Is<string>(..) for arg of type object).
* [NEW] NSubstitute website and documentation http://nsubstitute.github.com
* [FIX] Formating for argument matchers that take predicate functions.
* [FIX] Match single argument matcher passed to params arg (#34)
* [FIX] Detect ambiguous arg matchers in additional case (#31)
* [FIX] Can modify event handler subscriptions from within event callback
* [UPDATE] Update to Castle.Core 2.5.2
* [FIX] Can substitute for SynchronizationContext in .NET4 (fixed in Castle.Core)
* [NEW] NSubstitute available as NuPack package
### 0.9.0 Beta 1
* [FIX] Now handles argument specifiers used for params arguments correctly
* [UPDATE] Updated to Castle.Core 2.5 final.
### 0.1.3 alpha 4
* [NEW] Support auto/recursive substituting for members that return interfaces or delegates.
* [NEW] Support auto substituting for members that return arrays and strings (return empty values rather than null).
* [NEW] Raise.Event<TEventArgs>() will now attempt to construct arguments with default ctors, so in most cases they will not need to be explictly provided.
* [UPDATE] Added support for raising events with custom delegate types.
* [UPDATE] Formatting for event subscription and unsubscription calls in call received/not received exceptions.
* [UPDATE] Updated to pre-release build of Castle.Core 2.5 to get dynamic proxy to support modopts.
* [FIX] Throw correct exception when raising an event and event handler throws. (Fix by Rodrigo Perera)
* [FIX] Record call as received when it throws an exception from the When..Do callback.
### 0.1.2 alpha 3
* [NEW] Marked non-matching parameters in the actual calls listed for CallNotReceivedException messages.
* [NEW] Added WhenForAnyArgs..Do syntax for callbacks.
* [UPDATE] Updated arg matching to be smarter when matchers are not used for all args.
* [FIX] Fixed bug when substituting for delegates with multiple parameters.
* [FIX] Removed redundant cast operator which sometimes caused the compiler trouble in resolving Raise.Event().
### 0.1.1 alpha 2
* [NEW] Added ReturnsForAnyArgs() extension methods
* [FIX] Compiled for Any CPU to run on x64 platforms
### 0.1.0 alpha
* Initial release

View File

@@ -1,27 +0,0 @@
Copyright (c) 2009 Anthony Egerton (nsubstitute@delfish.com) and David Tchepak (dave@davesquared.net)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the names of the copyright holders nor the names of
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[ http://www.opensource.org/licenses/bsd-license.php ]

View File

@@ -1,113 +0,0 @@
NSubstitute
========
Visit the [NSubstitute website](http://nsubstitute.github.com) for more information.
### What is it?
NSubstitute is designed as a friendly substitute for .NET mocking libraries.
It is an attempt to satisfy our craving for a mocking library with a succinct syntax that helps us keep the focus on the intention of our tests, rather than on the configuration of our test doubles. We've tried to make the most frequently required operations obvious and easy to use, keeping less usual scenarios discoverable and accessible, and all the while maintaining as much natural language as possible.
Perfect for those new to testing, and for others who would just like to to get their tests written with less noise and fewer lambdas.
### Getting help
If you have questions or feedback on NSubstitute, head on over to the [NSubstitute discussion group](http://groups.google.com/group/nsubstitute).
### Basic use
Let's say we have a basic calculator interface:
public interface ICalculator
{
int Add(int a, int b);
string Mode { get; set; }
event Action PoweringUp;
}
We can ask NSubstitute to create a substitute instance for this type. We could ask for a stub, mock, fake, spy, test double etc., but why bother when we just want to substitute an instance we have some control over?
_calculator = Substitute.For<ICalculator>();
Now we can tell our substitute to return a value for a call:
_calculator.Add(1, 2).Returns(3);
Assert.That(_calculator.Add(1, 2), Is.EqualTo(3));
We can check that our substitute received a call, and did not receive others:
_calculator.Add(1, 2);
_calculator.Received().Add(1, 2);
_calculator.DidNotReceive().Add(5, 7);
If our Received() assertion fails, NSubstitute tries to give us some help as to what the problem might be:
NSubstitute.Exceptions.ReceivedCallsException : Expected to receive a call matching:
Add(1, 2)
Actually received no matching calls.
Received 2 non-matching calls (non-matching arguments indicated with '*' characters):
Add(1, *5*)
Add(*4*, *7*)
We can also work with properties using the Returns syntax we use for methods, or just stick with plain old property setters (for read/write properties):
_calculator.Mode.Returns("DEC");
Assert.That(_calculator.Mode, Is.EqualTo("DEC"));
_calculator.Mode = "HEX";
Assert.That(_calculator.Mode, Is.EqualTo("HEX"));
NSubstitute supports argument matching for setting return values and asserting a call was received:
_calculator.Add(10, -5);
_calculator.Received().Add(10, Arg.Any<int>());
_calculator.Received().Add(10, Arg.Is<int>(x => x < 0));
We can use argument matching as well as passing a function to Returns() to get some more behaviour out of our substitute (possibly too much, but that's your call):
_calculator
.Add(Arg.Any<int>(), Arg.Any<int>())
.Returns(x => (int)x[0] + (int)x[1]);
Assert.That(_calculator.Add(5, 10), Is.EqualTo(15));
Returns() can also be called with multiple arguments to set up a sequence of return values.
_calculator.Mode.Returns("HEX", "DEC", "BIN");
Assert.That(_calculator.Mode, Is.EqualTo("HEX"));
Assert.That(_calculator.Mode, Is.EqualTo("DEC"));
Assert.That(_calculator.Mode, Is.EqualTo("BIN"));
Finally, we can raise events on our substitutes (unfortunately C# dramatically restricts the extent to which this syntax can be cleaned up):
bool eventWasRaised = false;
_calculator.PoweringUp += () => eventWasRaised = true;
_calculator.PoweringUp += Raise.Event<Action>();
Assert.That(eventWasRaised);
### Building
If you have Visual Studio 2008, 2010, 2012, 2013, or 2015 you should be able to compile NSubstitute and run the unit tests using the NUnit GUI or console test runner (see the ThirdParty directory). Note that some tests are marked `[Pending]` and are not meant to pass at present, so it is a good idea to exclude tests in the Pending category from test runs.
To do full builds you'll also need Ruby, as the jekyll gem is used to generate the website.

View File

@@ -1,54 +0,0 @@
The aim of this file is to acknowledge the software projects that have been used to create NSubstitute, particularly those distributed as Open Source Software. They have been invaluable in helping us produce this software.
# Software distributed with/compiled into NSubstitute
## Castle.Core
NSubstitute is built on the Castle.Core library, particularly Castle.DynamicProxy which is used for generating proxies for types and intercepting calls made to them so that NSubstitute can record them.
Castle.Core is maintained by the Castle Project [http://www.castleproject.org/] and is released under the Apache License, Version 2.0 [http://www.apache.org/licenses/LICENSE-2.0.html].
# Software used to help build NSubstitute
## NUnit [http://www.nunit.org/]
NUnit is used for coding and running unit and integration tests for NSubstitute. It is distributed under an open source zlib/libpng based license [http://www.opensource.org/licenses/zlib-license.html].
## Rhino Mocks [http://www.ayende.com/projects/rhino-mocks.aspx]
Used for mocking parts of the NSubstitute mocking framework for testing. It is distributed under the BSD license [http://www.opensource.org/licenses/bsd-license.php].
## Moq [http://moq.me/]
Moq is not used in NSubstitute, but was a great source of inspiration. Moq pioneered Arrange-Act-Assert (AAA) mocking syntax for .NET, as well as removing the distinction between mocks and stubs, both of which have become important parts of NSubstitute. Moq is available under the BSD license [http://www.opensource.org/licenses/bsd-license.php].
## NuPack [http://nupack.codeplex.com/]
Used for packaging NSubstitute for distribution as a nu package. Distributed under the Apache License, Version 2.0 [http://www.apache.org/licenses/LICENSE-2.0.html].
## Jekyll [http://jekyllrb.com/]
Static website generator written in Ruby, used for NSubstitute's website and documentation. Distributed under the MIT license [http://www.opensource.org/licenses/bsd-license.php].
## SyntaxHighlighter [http://alexgorbatchev.com/SyntaxHighlighter/]
Open source, JavaScript, client-side code highlighter used for highlighting code samples on the NSubstitute website. Distributed under the MIT License [http://en.wikipedia.org/wiki/MIT_License] and the GPL [http://www.gnu.org/copyleft/lesser.html].
## FAKE [http://fsharp.github.io/FAKE/]
FAKE (F# Make) is used for NSubstitute's build. It is inspired by `make` and `rake`. FAKE is distributed under a dual Apache 2 / MS-PL license [https://github.com/fsharp/FAKE/blob/master/License.txt].
## Microsoft .NET Framework [http://www.microsoft.com/net/]
NSubstitute is coded in C# and compiled using Microsoft .NET. It can also run and compile under Mono [http://www.mono-project.com], an open source implementation of the open .NET standards for C# and the CLI.
Microsoft's .NET Framework is available under a EULA (and possibly other licenses like MS Reference Source License).
Mono is available under four open source licenses for different parts of the project (including MIT/X11, GPL, MS-Pl). These are described on the project site [http://www.mono-project.com/Licensing].
## Microsoft Ilmerge [http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx]
Used for combining assemblies so NSubstitute can be distributed as a single DLL. Available for use under a EULA as described on the ilmerge site.
## Microsoft Reactive Extensions for .NET (Rx) [http://msdn.microsoft.com/en-us/devlabs/ee794896]
Used to provide .NET 3.5 with some of the neat concurrency helper classes that ship with out of the box with .NET 4.0. Distributed under a EULA [http://msdn.microsoft.com/en-us/devlabs/ff394099].
## 7-Zip [http://www.7-zip.org/]
7-zip is used to ZIP up NSubstitute distributions as part of the automated build process. Distributed under a mixed GNU LGPL / unRAR licence [http://www.7-zip.org/license.txt].
# Other acknowledgements
## Software developers
Yes, you! To everyone who has tried to get better at the craft and science of programming, especially those of you who have talked, tweeted, blogged, screencasted, and/or contributed software or ideas to the community.
No software developers were harmed to any significant extent during the production of NSubstitute, although some had to get by on reduced sleep.

View File

@@ -1,719 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>NSubstitute</name>
</assembly>
<members>
<member name="T:NSubstitute.Arg">
<summary>
Argument matchers used for specifying calls to substitutes.
</summary>
</member>
<member name="M:NSubstitute.Arg.Any``1">
<summary>
Match any argument value compatible with type <typeparamref name="T"/>.
</summary>
<typeparam name="T"></typeparam>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Is``1(``0)">
<summary>
Match argument that is equal to <paramref name="value"/>.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Is``1(System.Linq.Expressions.Expression{System.Predicate{``0}})">
<summary>
Match argument that satisfies <paramref name="predicate"/>.
If the <paramref name="predicate"/> throws an exception for an argument it will be treated as non-matching.
</summary>
<typeparam name="T"></typeparam>
<param name="predicate"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Invoke">
<summary>
Invoke any <see cref="T:System.Action"/> argument whenever a matching call is made to the substitute.
</summary>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Invoke``1(``0)">
<summary>
Invoke any <see cref="T:System.Action`1"/> argument with specified argument whenever a matching call is made to the substitute.
</summary>
<typeparam name="T"></typeparam>
<param name="arg"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Invoke``2(``0,``1)">
<summary>
Invoke any <see cref="T:System.Action`2"/> argument with specified arguments whenever a matching call is made to the substitute.
</summary>
<typeparam name="T1"></typeparam>
<typeparam name="T2"></typeparam>
<param name="arg1"></param>
<param name="arg2"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Invoke``3(``0,``1,``2)">
<summary>
Invoke any <see cref="T:System.Action`3"/> argument with specified arguments whenever a matching call is made to the substitute.
</summary>
<typeparam name="T1"></typeparam>
<typeparam name="T2"></typeparam>
<typeparam name="T3"></typeparam>
<param name="arg1"></param>
<param name="arg2"></param>
<param name="arg3"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Invoke``4(``0,``1,``2,``3)">
<summary>
Invoke any <see cref="T:System.Action`4"/> argument with specified arguments whenever a matching call is made to the substitute.
</summary>
<typeparam name="T1"></typeparam>
<typeparam name="T2"></typeparam>
<typeparam name="T3"></typeparam>
<typeparam name="T4"></typeparam>
<param name="arg1"></param>
<param name="arg2"></param>
<param name="arg3"></param>
<param name="arg4"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.InvokeDelegate``1(System.Object[])">
<summary>
Invoke any <typeparamref name="TDelegate"/> argument with specified arguments whenever a matching call is made to the substitute.
</summary>
<typeparam name="TDelegate"></typeparam>
<param name="arguments">Arguments to pass to delegate.</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Arg.Do``1(System.Action{``0})">
<summary>
Capture any argument compatible with type <typeparamref name="T"/> and use it to call the <paramref name="useArgument"/> function
whenever a matching call is made to the substitute.
</summary>
<typeparam name="T"></typeparam>
<param name="useArgument"></param>
<returns></returns>
</member>
<member name="T:NSubstitute.Callback">
<summary>
Perform this chain of callbacks and/or always callback when called.
</summary>
</member>
<member name="M:NSubstitute.Callback.First(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Perform as first in chain of callback when called.
</summary>
<param name="doThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callback.Always(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Perform this action always when callback is called.
</summary>
<param name="doThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callback.FirstThrow``1(System.Func{NSubstitute.Core.CallInfo,``0})">
<summary>
Throw exception returned by function as first callback in chain of callback when called.
</summary>
<param name="throwThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callback.FirstThrow``1(``0)">
<summary>
Throw this exception as first callback in chain of callback when called.
</summary>
<param name="exception"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callback.AlwaysThrow``1(System.Func{NSubstitute.Core.CallInfo,``0})">
<summary>
Throw exception returned by function always when callback is called.
</summary>
<typeparam name="TException">The type of the exception.</typeparam>
<param name="throwThis">The throw this.</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callback.AlwaysThrow``1(``0)">
<summary>
Throw this exception always when callback is called.
</summary>
<typeparam name="TException">The type of the exception.</typeparam>
<param name="exception">The exception.</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.EndCallbackChain.AndAlways(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Perform the given action for every call.
</summary>
<param name="doThis">The action to perform for every call</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.ConfiguredCallback.Then(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Perform this action once in chain of called callbacks.
</summary>
<param name="doThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.ConfiguredCallback.ThenKeepDoing(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Keep doing this action after the other callbacks have run.
</summary>
<param name="doThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.ConfiguredCallback.ThenKeepThrowing``1(System.Func{NSubstitute.Core.CallInfo,``0})">
<summary>
Keep throwing this exception after the other callbacks have run.
</summary>
<typeparam name="TException"></typeparam>
<param name="throwThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.ConfiguredCallback.ThenKeepThrowing``1(``0)">
<summary>
Keep throwing this exception after the other callbacks have run.
</summary>
<typeparam name="TException"></typeparam>
<param name="throwThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.ConfiguredCallback.ThenThrow``1(System.Func{NSubstitute.Core.CallInfo,``0})">
<summary>
Throw exception returned by function once when called in a chain of callbacks.
</summary>
<typeparam name="TException">The type of the exception</typeparam>
<param name="throwThis">Produce the exception to throw for a CallInfo</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Callbacks.ConfiguredCallback.ThenThrow``1(``0)">
<summary>
Throw this exception once when called in a chain of callbacks.
</summary>
<typeparam name="TException">The type of the exception</typeparam>
<param name="exception">The exception to throw</param>
<returns></returns>
</member>
<member name="T:NSubstitute.Core.Arguments.IArgumentMatcher">
<summary>
Provides a specification for arguments for use with <see ctype="Arg.Matches (IArgumentMatcher)" />.
Can additionally implement <see ctype="IDescribeNonMatches" /> to give descriptions when arguments do not match.
</summary>
</member>
<member name="M:NSubstitute.Core.Arguments.IArgumentMatcher.IsSatisfiedBy(System.Object)">
<summary>
Checks whether the <paramref name="argument"/> satisfies the condition of the matcher.
If this throws an exception the argument will be treated as non-matching.
</summary>
<param name="argument"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Core.IDescribeNonMatches.DescribeFor(System.Object)">
<summary>
Describes how the <paramref name="argument"/> does not match the condition specified by this class, or <see cref="F:System.String.Empty"/>
if a detailed description can not be provided for the argument.
</summary>
<param name="argument"></param>
<returns>Description of the non-match, or <see cref="F:System.String.Empty"/> if no description can be provided.</returns>
</member>
<member name="M:NSubstitute.Core.ConfiguredCall.AndDoes(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Adds a callback to execute for matching calls.
</summary>
<param name="action">an action to call</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Core.Extensions.Zip``3(System.Collections.Generic.IEnumerable{``0},System.Collections.Generic.IEnumerable{``1},System.Func{``0,``1,``2})">
<summary>
Combines two enumerables into a new enumerable using the given selector.
</summary>
<typeparam name="TFirst"></typeparam>
<typeparam name="TSecond"></typeparam>
<typeparam name="TResult"></typeparam>
<param name="first"></param>
<param name="second"></param>
<param name="selector"></param>
<returns></returns>
<remarks>
This implementation was sanity-checked against the
<a href="http://msmvps.com/blogs/jon_skeet/archive/2011/01/14/reimplementing-linq-to-objects-part-35-zip.aspx">Edulinq implementation</a> and
<a href="http://blogs.msdn.com/b/ericlippert/archive/2009/05/07/zip-me-up.aspx">Eric Lippert's implementation</a>.
</remarks>
</member>
<member name="M:NSubstitute.Core.Extensions.IsCompatibleWith(System.Object,System.Type)">
<summary>
Checks if the instance can be used when a <paramref name="type"/> is expected.
</summary>
<param name="instance"></param>
<param name="type"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Core.Extensions.Join(System.Collections.Generic.IEnumerable{System.String},System.String)">
<summary>
Join the <paramref name="strings"/> using <paramref name="seperator"/>.
</summary>
<param name="strings"></param>
<param name="seperator"></param>
<returns></returns>
</member>
<member name="T:NSubstitute.Core.Maybe`1">
<summary>
Particularly poor implementation of Maybe/Option type.
This is just filling an immediate need; use FSharpOption or XSharpx or similar for a
real implementation.
</summary>
<typeparam name="T"></typeparam>
</member>
<member name="T:NSubstitute.Core.RobustThreadLocal`1">
<summary>
Delegates to ThreadLocal&lt;T&gt;, but wraps Value property access in try/catch to swallow ObjectDisposedExceptions.
These can occur if the Value property is accessed from the finalizer thread. Because we can't detect this, we'll
just swallow the exception (the finalizer thread won't be using any of the values from thread local storage anyway).
</summary>
<typeparam name="T"></typeparam>
</member>
<member name="F:NSubstitute.Core.SubstituteConfig.OverrideAllCalls">
<summary>
Standard substitute behaviour; replace all calls with substituted behaviour.
</summary>
</member>
<member name="F:NSubstitute.Core.SubstituteConfig.CallBaseByDefault">
<summary>
Partial substitute; use base behaviour unless explicitly overriden.
</summary>
</member>
<member name="M:NSubstitute.ExceptionExtensions.ExceptionExtensions.Throws(System.Object,System.Exception)">
<summary>
Throw an exception for this call.
</summary>
<param name="value"></param>
<param name="ex">Exception to throw</param>
<returns></returns>
</member>
<member name="M:NSubstitute.ExceptionExtensions.ExceptionExtensions.Throws``1(System.Object)">
<summary>
Throw an exception of the given type for this call.
</summary>
<typeparam name="TException">Type of exception to throw</typeparam>
<param name="value"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.ExceptionExtensions.ExceptionExtensions.Throws(System.Object,System.Func{NSubstitute.Core.CallInfo,System.Exception})">
<summary>
Throw an exception for this call, as generated by the specified function.
</summary>
<param name="value"></param>
<param name="createException">Func creating exception object</param>
<returns></returns>
</member>
<member name="M:NSubstitute.ExceptionExtensions.ExceptionExtensions.ThrowsForAnyArgs(System.Object,System.Exception)">
<summary>
Throw an exception for this call made with any arguments.
</summary>
<param name="value"></param>
<param name="ex">Exception to throw</param>
<returns></returns>
</member>
<member name="M:NSubstitute.ExceptionExtensions.ExceptionExtensions.ThrowsForAnyArgs``1(System.Object)">
<summary>
Throws an exception of the given type for this call made with any arguments.
</summary>
<typeparam name="TException">Type of exception to throw</typeparam>
<param name="value"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.ExceptionExtensions.ExceptionExtensions.ThrowsForAnyArgs(System.Object,System.Func{NSubstitute.Core.CallInfo,System.Exception})">
<summary>
Throws an exception for this call made with any arguments, as generated by the specified function.
</summary>
<param name="value"></param>
<param name="createException">Func creating exception object</param>
<returns></returns>
</member>
<member name="M:NSubstitute.Experimental.Received.InOrder(System.Action)">
<summary>
*EXPERIMENTAL* Asserts the calls to the substitutes contained in the given Action were
received by these substitutes in the same order. Calls to property getters are not included
in the assertion.
</summary>
<param name="calls">Action containing calls to substitutes in the expected order</param>
</member>
<member name="T:NSubstitute.Core.Arguments.IArgumentMatcher`1">
<summary>
Provides a specification for arguments for use with <see ctype="Arg.Matches &lt; T &gt;(IArgumentMatcher)" />.
Can additionally implement <see ctype="IDescribeNonMatches" /> to give descriptions when arguments do not match.
</summary>
<typeparam name="T">Matches arguments of type <typeparamref name="T"/> or compatible type.</typeparam>
</member>
<member name="M:NSubstitute.Core.Arguments.IArgumentMatcher`1.IsSatisfiedBy(`0)">
<summary>
Checks whether the <paramref name="argument"/> satisfies the condition of the matcher.
If this throws an exception the argument will be treated as non-matching.
</summary>
<param name="argument"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Extensions.ReturnsForAllExtensions.ReturnsForAll``1(System.Object,``0)">
<summary>
Configure default return value for all methods that return the specified type
</summary>
<typeparam name="T"></typeparam>
<param name = "substitute"></param>
<param name="returnThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Extensions.ReturnsForAllExtensions.ReturnsForAll``1(System.Object,System.Func{NSubstitute.Core.CallInfo,``0})">
<summary>
Configure default return value for all methods that return the specified type, calculated by a function
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<param name="returnThis"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Received.InOrder(System.Action)">
<summary>
Asserts the calls to the substitutes contained in the given Action were
received by these substitutes in the same order. Calls to property getters are not included
in the assertion.
</summary>
<param name="calls">Action containing calls to substitutes in the expected order</param>
</member>
<member name="T:NSubstitute.Routing.Handlers.ClearLastCallRouterHandler">
<summary>
Clears last call router on SubstitutionContext for routes that do not require it.
</summary>
<remarks>
This is to help prevent static state bleeding over into future calls.
</remarks>
</member>
<member name="M:NSubstitute.Core.CallInfo.Args">
<summary>
Get the arguments passed to this call.
</summary>
<returns>Array of all arguments passed to this call</returns>
</member>
<member name="M:NSubstitute.Core.CallInfo.ArgTypes">
<summary>
Gets the types of all the arguments passed to this call.
</summary>
<returns>Array of types of all arguments passed to this call</returns>
</member>
<member name="M:NSubstitute.Core.CallInfo.Arg``1">
<summary>
Gets the argument of type `T` passed to this call. This will throw if there are no arguments
of this type, or if there is more than one matching argument.
</summary>
<typeparam name="T">The type of the argument to retrieve</typeparam>
<returns>The argument passed to the call, or throws if there is not exactly one argument of this type</returns>
</member>
<member name="M:NSubstitute.Core.CallInfo.ArgAt``1(System.Int32)">
<summary>
Gets the argument passed to this call at the specified position converted to type `T`.
This will throw if there are no arguments, if the argument is out of range or if it
cannot be converted to the specified type.
</summary>
<typeparam name="T">The type of the argument to retrieve</typeparam>
<param name="position"></param>
<returns>The argument passed to the call, or throws if there is not exactly one argument of this type</returns>
</member>
<member name="P:NSubstitute.Core.CallInfo.Item(System.Int32)">
<summary>
Gets the nth argument to this call.
</summary>
<param name="index">Index of argument</param>
<returns>The value of the argument at the given index</returns>
</member>
<member name="M:NSubstitute.Raise.EventWith``1(System.Object,``0)">
<summary>
Raise an event for an <c>EventHandler&lt;TEventArgs&gt;</c> event with the provided <paramref name="sender"/> and <paramref name="eventArgs"/>.
</summary>
</member>
<member name="M:NSubstitute.Raise.EventWith``1(``0)">
<summary>
Raise an event for an <c>EventHandler&lt;TEventArgs&gt;</c> event with the substitute as the sender and the provided <paramref name="eventArgs" />.
</summary>
</member>
<member name="M:NSubstitute.Raise.EventWith``1">
<summary>
Raise an event for an <c>EventHandler&lt;EventArgsT&gt;</c> event with the substitute as the sender
and with a default instance of <typeparamref name="TEventArgs" />.
</summary>
</member>
<member name="M:NSubstitute.Raise.Event">
<summary>
Raise an event for an <c>EventHandler</c> or <c>EventHandler&lt;EventArgs&gt;</c> event with the substitute
as the sender and with empty <c>EventArgs</c>.
</summary>
</member>
<member name="M:NSubstitute.Raise.Event``1(System.Object[])">
<summary>
Raise an event of type <typeparamref name="THandler" /> with the provided arguments. If no arguments are provided
NSubstitute will try to provide reasonable defaults.
</summary>
</member>
<member name="T:NSubstitute.Substitute">
<summary>
Create a substitute for one or more types. For example: <c>Substitute.For&lt;ISomeType&gt;()</c>
</summary>
</member>
<member name="M:NSubstitute.Substitute.For``1(System.Object[])">
<summary>
Substitute for an interface or class.
<para>Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members
can be recorded or have return values specified.</para>
</summary>
<typeparam name="T">The type of interface or class to substitute.</typeparam>
<param name="constructorArguments">Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors.</param>
<returns>A substitute for the interface or class.</returns>
</member>
<member name="M:NSubstitute.Substitute.For``2(System.Object[])">
<summary>
<para>Substitute for multiple interfaces or a class that implements an interface. At most one class can be specified.</para>
<para>Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members
can be recorded or have return values specified.</para>
</summary>
<typeparam name="T1">The type of interface or class to substitute.</typeparam>
<typeparam name="T2">An additional interface or class (maximum of one class) the substitute should implement.</typeparam>
<param name="constructorArguments">Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors.</param>
<returns>A substitute of type T1, that also implements T2.</returns>
</member>
<member name="M:NSubstitute.Substitute.For``3(System.Object[])">
<summary>
<para>Substitute for multiple interfaces or a class that implements multiple interfaces. At most one class can be specified.</para>
If additional interfaces are required use the <see cref="M:NSubstitute.Substitute.For(System.Type[],System.Object[])"/> overload.
<para>Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members
can be recorded or have return values specified.</para>
</summary>
<typeparam name="T1">The type of interface or class to substitute.</typeparam>
<typeparam name="T2">An additional interface or class (maximum of one class) the substitute should implement.</typeparam>
<typeparam name="T3">An additional interface or class (maximum of one class) the substitute should implement.</typeparam>
<param name="constructorArguments">Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors.</param>
<returns>A substitute of type T1, that also implements T2 and T3.</returns>
</member>
<member name="M:NSubstitute.Substitute.For(System.Type[],System.Object[])">
<summary>
<para>Substitute for multiple interfaces or a class that implements multiple interfaces. At most one class can be specified.</para>
<para>Be careful when specifying a class, as all non-virtual members will actually be executed. Only virtual members
can be recorded or have return values specified.</para>
</summary>
<param name="typesToProxy">The types of interfaces or a type of class and multiple interfaces the substitute should implement.</param>
<param name="constructorArguments">Arguments required to construct a class being substituted. Not required for interfaces or classes with default constructors.</param>
<returns>A substitute implementing the specified types.</returns>
</member>
<member name="M:NSubstitute.Substitute.ForPartsOf``1(System.Object[])">
<summary>
Create a substitute for a class that behaves just like a real instance of the class, but also
records calls made to its virtual members and allows for specific members to be substituted
by using <see cref="M:NSubstitute.Core.WhenCalled`1.DoNotCallBase">When(() =&gt; call).DoNotCallBase()</see> or by
<see cref="M:NSubstitute.SubstituteExtensions.Returns``1(``0,``0,``0[])">setting a value to return value</see> for that member.
</summary>
<typeparam name="T">The type to substitute for parts of. Must be a class; not a delegate or interface.</typeparam>
<param name="constructorArguments"></param>
<returns>An instance of the class that will execute real methods when called, but allows parts to be selectively
overridden via `Returns` and `When..DoNotCallBase`.</returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.Returns``1(``0,``0,``0[])">
<summary>
Set a return value for this call.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<param name="returnThis">Value to return</param>
<param name="returnThese">Optionally return these values next</param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.Returns``1(``0,System.Func{NSubstitute.Core.CallInfo,``0},System.Func{NSubstitute.Core.CallInfo,``0}[])">
<summary>
Set a return value for this call, calculated by the provided function.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<param name="returnThis">Function to calculate the return value</param>
<param name="returnThese">Optionally use these functions next</param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.ReturnsForAnyArgs``1(``0,``0,``0[])">
<summary>
Set a return value for this call made with any arguments.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<param name="returnThis">Value to return</param>
<param name="returnThese">Optionally return these values next</param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.ReturnsForAnyArgs``1(``0,System.Func{NSubstitute.Core.CallInfo,``0},System.Func{NSubstitute.Core.CallInfo,``0}[])">
<summary>
Set a return value for this call made with any arguments, calculated by the provided function.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<param name="returnThis">Function to calculate the return value</param>
<param name="returnThese">Optionally use these functions next</param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.Received``1(``0)">
<summary>
Checks this substitute has received the following call.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.Received``1(``0,System.Int32)">
<summary>
Checks this substitute has received the following call the required number of times.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<param name="requiredNumberOfCalls"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.DidNotReceive``1(``0)">
<summary>
Checks this substitute has not received the following call.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.ReceivedWithAnyArgs``1(``0)">
<summary>
Checks this substitute has received the following call with any arguments.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.ReceivedWithAnyArgs``1(``0,System.Int32)">
<summary>
Checks this substitute has received the following call with any arguments the required number of times.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<param name="requiredNumberOfCalls"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.DidNotReceiveWithAnyArgs``1(``0)">
<summary>
Checks this substitute has not received the following call with any arguments.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.ClearReceivedCalls``1(``0)">
<summary>
Forget all the calls this substitute has received.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<remarks>
Note that this will not clear any results set up for the substitute using Returns().
</remarks>
</member>
<member name="M:NSubstitute.SubstituteExtensions.When``1(``0,System.Action{``0})">
<summary>
Perform an action when this member is called.
Must be followed by <see cref="M:NSubstitute.Core.WhenCalled`1.Do(System.Action{NSubstitute.Core.CallInfo})"/> to provide the callback.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<param name="substituteCall"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.WhenForAnyArgs``1(``0,System.Action{``0})">
<summary>
Perform an action when this member is called with any arguments.
Must be followed by <see cref="M:NSubstitute.Core.WhenCalled`1.Do(System.Action{NSubstitute.Core.CallInfo})"/> to provide the callback.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<param name="substituteCall"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.SubstituteExtensions.ReceivedCalls``1(``0)">
<summary>
Returns the calls received by this substitute.
</summary>
<typeparam name="T"></typeparam>
<param name="substitute"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Core.SubstituteFactory.Create(System.Type[],System.Object[])">
<summary>
Create a substitute for the given types.
</summary>
<param name="typesToProxy"></param>
<param name="constructorArguments"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Core.SubstituteFactory.CreatePartial(System.Type[],System.Object[])">
<summary>
Create an instance of the given types, with calls configured to call the base implementation
where possible. Parts of the instance can be substituted using
<see cref="M:NSubstitute.SubstituteExtensions.Returns``1(``0,``0,``0[])">Returns()</see>.
</summary>
<param name="typesToProxy"></param>
<param name="constructorArguments"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.Core.WhenCalled`1.Do(System.Action{NSubstitute.Core.CallInfo})">
<summary>
Perform this action when called.
</summary>
<param name="callbackWithArguments"></param>
</member>
<member name="M:NSubstitute.Core.WhenCalled`1.Do(NSubstitute.Callback)">
<summary>
Perform this configured callcback when called.
</summary>
<param name="callback"></param>
</member>
<member name="M:NSubstitute.Core.WhenCalled`1.DoNotCallBase">
<summary>
Do not call the base implementation on future calls. For use with partial substitutes.
</summary>
</member>
<member name="M:NSubstitute.Core.WhenCalled`1.Throw(System.Exception)">
<summary>
Throw the specified exception when called.
</summary>
</member>
<member name="M:NSubstitute.Core.WhenCalled`1.Throw``1">
<summary>
Throw an exception of the given type when called.
</summary>
</member>
<member name="M:NSubstitute.Core.WhenCalled`1.Throw(System.Func{NSubstitute.Core.CallInfo,System.Exception})">
<summary>
Throw an exception generated by the specified function when called.
</summary>
</member>
<member name="M:NSubstitute.ReturnsExtensions.ReturnsExtensions.ReturnsNull``1(``0)">
<summary>
Set null as returned value for this call.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<returns></returns>
</member>
<member name="M:NSubstitute.ReturnsExtensions.ReturnsExtensions.ReturnsNullForAnyArgs``1(``0)">
<summary>
Set null as returned value for this call made with any arguments.
</summary>
<typeparam name="T"></typeparam>
<param name="value"></param>
<returns></returns>
</member>
</members>
</doc>

Some files were not shown because too many files have changed in this diff Show More