Open xperia-droid opened 4 months ago
May I ask how were you able to change RDCMAN.exe? I did download DNSPY, and opened RDCMAN.exe, then navigated to RdcMan --> MainForm, but I have no idea how to add those lines of code that you wrote above. Sorry for the noob question, but I'm not familiar with coding etc.
Hi @Simke771,
your first steps were so far correct.
On the first function you right click inside the "Function private MainForm() and then click on "Edit method" in the contextmenu. There you can change The code as you like.
After you have finished the modifications on the Function you click on button "Compile" on the bottom right. If the changed code is correct, the modification window disappears and you can see the new code in the DNSPY tab.
When You have made all the changes you wanted. You go in the Menu on File -> Save Module. In the New Window you can set an new name in the path (example: RDCMAN_dark.exe) and click on OK to save the file.
Thank you @xperia-droid for your fast reply, but it seems like I'm still doing something wrong. Even when I just open Edit Method, and don't change anything, Complie will fail with a bunch of errors. Adding your code to it, just increases number of errors. Hopefully you can point me in the right direction.
Also not sure if I'm adding your code correctly, but like I said, my first problem is that compile doesn't work even when I do zero changes to it.
Original looks like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace RdcMan
{
// Token: 0x02000067 RID: 103
internal partial class MainForm : RdcBaseForm, IMainForm
{
// Token: 0x060002A1 RID: 673 RVA: 0x0000F300 File Offset: 0x0000D500
private MainForm()
{
Dictionary<Keys, Action> dictionary = new Dictionary<Keys, Action>();
dictionary.Add((Keys)131150, delegate
{
this.OnFileNew();
});
dictionary.Add((Keys)131151, delegate
{
this.OnFileOpen();
});
dictionary.Add((Keys)131155, delegate
{
this.OnFileSave();
});
dictionary.Add((Keys)131137, delegate
{
AddNodeDialogHelper.AddServersDialog();
});
dictionary.Add((Keys)131143, delegate
{
AddNodeDialogHelper.AddGroupDialog();
});
dictionary.Add((Keys)131142, delegate
{
MenuHelper.FindServers();
});
dictionary.Add((Keys)131153, delegate
{
MenuHelper.ConnectTo();
});
this.Shortcuts = dictionary;
Dictionary<Keys, Action<RdcTreeNode>> dictionary2 = new Dictionary<Keys, Action<RdcTreeNode>>();
dictionary2.Add(Keys.Delete, delegate(RdcTreeNode node)
{
ServerTree.Instance.ConfirmRemove(node, true);
});
dictionary2.Add(Keys.RButton | Keys.MButton | Keys.Back | Keys.Space | Keys.Shift, delegate(RdcTreeNode node)
{
ServerTree.Instance.ConfirmRemove(node, false);
});
dictionary2.Add(Keys.Return, delegate(RdcTreeNode node)
{
node.Connect();
});
dictionary2.Add(Keys.LButton | Keys.MButton | Keys.Back | Keys.Shift, delegate(RdcTreeNode node)
{
ServerBase serverBase = node as ServerBase;
bool isConnected;
if (serverBase != null)
{
isConnected = serverBase.IsConnected;
}
else
{
bool flag;
(node as GroupBase).AnyOrAllConnected(out flag, out isConnected);
}
if (!isConnected)
{
node.DoConnectAs();
}
});
dictionary2.Add(Keys.LButton | Keys.MButton | Keys.Back | Keys.Alt, delegate(RdcTreeNode node)
{
if (node.HasProperties)
{
node.DoPropertiesDialog();
}
});
dictionary2.Add((Keys)131140, delegate(RdcTreeNode node)
{
MenuHelper.AddFavorite(node);
});
this.SelectedNodeShortcuts = dictionary2;
}
}
}
If I understand your original post it should be like this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
namespace RdcMan
{
// Token: 0x02000067 RID: 103
internal partial class MainForm : RdcBaseForm, IMainForm
{
// Token: 0x060002A1 RID: 673 RVA: 0x0000F300 File Offset: 0x0000D500
private MainForm()
{
this.BackColor = Color.FromArgb(255, 45, 45, 48);
this.ForeColor = Color.FromArgb(255, 241, 241, 241);
Dictionary<Keys, Action> dictionary = new Dictionary<Keys, Action>();
dictionary.Add((Keys)131150, delegate
{
this.OnFileNew();
});
dictionary.Add((Keys)131151, delegate
{
this.OnFileOpen();
});
dictionary.Add((Keys)131155, delegate
{
this.OnFileSave();
});
dictionary.Add((Keys)131137, delegate
{
AddNodeDialogHelper.AddServersDialog();
});
dictionary.Add((Keys)131143, delegate
{
AddNodeDialogHelper.AddGroupDialog();
});
dictionary.Add((Keys)131142, delegate
{
MenuHelper.FindServers();
});
dictionary.Add((Keys)131153, delegate
{
MenuHelper.ConnectTo();
});
this.Shortcuts = dictionary;
Dictionary<Keys, Action<RdcTreeNode>> dictionary2 = new Dictionary<Keys, Action<RdcTreeNode>>();
dictionary2.Add(Keys.Delete, delegate(RdcTreeNode node)
{
ServerTree.Instance.ConfirmRemove(node, true);
});
dictionary2.Add(Keys.RButton | Keys.MButton | Keys.Back | Keys.Space | Keys.Shift, delegate(RdcTreeNode node)
{
ServerTree.Instance.ConfirmRemove(node, false);
});
dictionary2.Add(Keys.Return, delegate(RdcTreeNode node)
{
node.Connect();
});
dictionary2.Add(Keys.LButton | Keys.MButton | Keys.Back | Keys.Shift, delegate(RdcTreeNode node)
{
ServerBase serverBase = node as ServerBase;
bool isConnected;
if (serverBase != null)
{
isConnected = serverBase.IsConnected;
}
else
{
bool flag;
(node as GroupBase).AnyOrAllConnected(out flag, out isConnected);
}
if (!isConnected)
{
node.DoConnectAs();
}
});
dictionary2.Add(Keys.LButton | Keys.MButton | Keys.Back | Keys.Alt, delegate(RdcTreeNode node)
{
if (node.HasProperties)
{
node.DoPropertiesDialog();
}
});
dictionary2.Add((Keys)131140, delegate(RdcTreeNode node)
{
MenuHelper.AddFavorite(node);
});
this.SelectedNodeShortcuts = dictionary2;
}
public void AddToClientPanel(Control client)
{
client.BackColor = Color.FromArgb(255, 45, 45, 48);
client.ForeColor = Color.FromArgb(255, 241, 241, 241);
this._clientPanel.Controls.Add(client);
}
}
}
Hi @Simke771,
interesting behavior, I can't reproduce it on my side. Somehow DNSPY uses .NET Framework 4.5 and .NET 5.0 simultaneously on your side and you get the error that Size exists in 2 variations.
If you send me your mail adress (or another file transfer link) I can send you my compiled executable to you. Because at the moment I don't know how to fix your issue.
An easy idea would be to remove .NET 5.0 from your installed programs, restart DNSPY and try again.
Hey @xperia-droid
You are correct, the problem was because I also have .NET 5.0 on my work computer since it was required for some other software that we are using. I tried to compile it on my other computer without .NET 5.0 and it works exactly as it should. Thanks again for your help, I can now finally use RDCMAN in dark mode :)
Hello @xperia-droid,
Thank you for this awesome post! Already 99% better and less painful on my eyes.
I was wondering if you could, when time permits, find out where one goes to change the title bar and contextmenus:
And this dialog forms:
And for the client area when a "not connected server" is clicked on:
As well, can this icon (or a better version of it) be used to replace the current to show it is the dark mode version: RDCMan_32512 (dark).zip
Pretty pretty please?
Hi @karynnglli,
I have read your post and I will go trough the easy steps to the hard ones.
To set the background of the thumbnail panels, you need to change the method "AddToClientPanel" in the MainForm class:
class MainForm
From
public void AddToClientPanel(Control client)
{
this._clientPanel.Controls.Add(client);
}
To
public void AddToClientPanel(Control client)
{
client.BackColor = Color.FromArgb(255, 45, 45, 48);
client.ForeColor = Color.FromArgb(255, 241, 241, 241);
this._clientPanel.Controls.Add(client);
}
Then compile the method.
For an dark title bar you have to make some code modifications on the class "RdcBaseForm". Here you have to edit the class from the contextmenu and not edit the method, because we have to add 2 new methods.
Copy this code
[DllImport("DwmApi")] //System.Runtime.InteropServices
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, int[] attrValue, int attrSize);
protected override void OnHandleCreated(EventArgs e)
{
if (DwmSetWindowAttribute(Handle, 19, new[] { 1 }, 4) != 0)
DwmSetWindowAttribute(Handle, 20, new[] { 1 }, 4);
}
And insert it under this line:
public abstract partial class RdcBaseForm : Form
{
Then compile the class.
Source from here: https://stackoverflow.com/a/64927217
To replace the Icons, we need to replace 2 different icons.
The Resource Icon is the Icon you see in the Title Bar on the left side.
In DnSpy scroll on the left side up to the top and open the Resources folder. Inside this folder are all internal Resources located.
We have to replace the resource called "RdcMan.Resources.app.ico".
The Manifest Icon is the Icon you see in the windows explorer. To be able to replace the Manifest Icon, save the current changes in DnSpy in an new executable under File -> Save Module...
You have to save this file, because we need another programm called Resource Hacker to be able to replace the manifest Icon.
After you saved the file, download the good old Resource Hacker from here: https://www.angusj.com/resourcehacker/ (The Downloads are on the bottom of the page) Direct zip file Link from the site: https://www.angusj.com/resourcehacker/resource_hacker.zip
Extract the zip file to an destination you like and open the file ResourceHacker.exe.
In Resource Hacker open the previous saved RDCMAN executable.
On the Left side you have an TreeView structure. RTight click on the folder called "Icon Group". In the context menu click on "Replace Icon ...". In the new window click on the button "Open file with new icon..." and search for your "RDCMan_32512 (dark).ico" and open it.
After you selected the icon click on the button "Replace".
Then in the main window of Resource Hacker click on "File" -> Save.
Now the Icon on the RDCMAN executable has been changed.
Sometimes after you make some changes with Resource Hacker you see the old Icon. The problem here lies with Explorer, as it caches the icons in an IconDB cache file.
To fix it, you can do one of the 2 following solutions:
For Clearing the Icon cache follow this process:
The elephant in the room is the MenuStrips and Contextmenu part.
The default MenuStrips / ContextMenus doesn't fit an dark theme and therefore are completly unreadable.
As an workaround I set the RenderMode of the MenuStrip to System. Because with this RenderMode you can have an dark Mode in the Title Bar and be able to read the content of the ContextMenus / MenuStrip.
I have made the change in the class RdcBaseForm (RdcBaseForm method) (From my first post).
this._menuStrip = new RdcMenuStrip
{
BackColor = Color.FromArgb(255, 45, 45, 48),
ForeColor = Color.FromArgb(255, 241, 241, 241),
RenderMode = ToolStripRenderMode.System,
Visible = true
};
If you switch the RenderMode to any other Option than System, compile the method, save the module and start it you will see what I mean.
To be able to set an dark mode RenderMode you have to create an new class and then set the RenderMode of the ToolStrip to the new generated class.
I don't know If you can add a new class with DnSpy to the RDCMan executable and then switch the RenderMode I need to test it.
For this part I will add an new post regarding my findings.
To create an dark Mode to the MenuStrip we have to add 2 classes: In DnSpy right click on the namespace RdcMan and click on "Add Class (C#)...".
In the new Window paste this code in:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace RdcMan
{
public class MyColorTable : ProfessionalColorTable
{
public override Color ToolStripDropDownBackground => Color.FromArgb(255, 45, 45, 48);
public override Color ImageMarginGradientBegin => Color.FromArgb(255, 45, 45, 48);
public override Color ImageMarginGradientMiddle => Color.FromArgb(255, 45, 45, 48);
public override Color ImageMarginGradientEnd => Color.FromArgb(255, 45, 45, 48);
public override Color MenuBorder => Color.Black;
public override Color MenuItemBorder => Color.Black;
public override Color MenuItemSelected => Color.FromArgb(255, 80, 80, 80);
public override Color MenuStripGradientBegin => Color.FromArgb(255, 45, 45, 48);
public override Color MenuStripGradientEnd => Color.FromArgb(255, 45, 45, 48);
public override Color MenuItemSelectedGradientBegin => Color.FromArgb(255, 51, 51, 52);
public override Color MenuItemSelectedGradientEnd => Color.FromArgb(255, 45, 45, 48);
public override Color MenuItemPressedGradientBegin => Color.FromArgb(255, 45, 45, 48);
public override Color MenuItemPressedGradientEnd => Color.FromArgb(255, 45, 45, 48);
}
}
Then click on compile.
For the next class to be added we have to save the Module, because the second class references the added class.
So click on File -> "Save Module...". You can save it with the same file name or choose an different executable name.
If you use the same name you click under File -> Reload All Assemblies to geload all files.
If you don't use the same name click under File -> "Close All" and then File -> "Open..." to open the new created file.
The reload / opening of the new file is required to add the new class. Otherwise you get an compile error on the next step.
After the reload right click again on the namespace RdcMan and click on "Add Class (C#)...".
This time you add this class:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace RdcMan
{
public class MyRenderer : ToolStripProfessionalRenderer
{
public MyRenderer() : base(new MyColorTable()) { }
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
{
e.TextColor = Color.White; // Set the text color to white
base.OnRenderItemText(e);
}
}
}
Then again we have to save the module under File -> "Save Module" and execute the same procedure as on the first class to reload the saved file.
We have to go trough this process again, because we need to reference the second generated class in the RdcBaseForm class.
Open the RdcBaseForm under the RdcMan namespace. Edit the method called "protected RdcBaseForm()" with right click on the method and select "Edit Method"
Replace this part:
this._menuStrip = new RdcMenuStrip
{
BackColor = Color.FromArgb(255, 45, 45, 48),
ForeColor = Color.FromArgb(255, 241, 241, 241),
RenderMode = ToolStripRenderMode.System,
Visible = true
};
With this
this._menuStrip = new RdcMenuStrip
{
BackColor = Color.FromArgb(255, 45, 45, 48),
ForeColor = Color.FromArgb(255, 241, 241, 241),
Renderer = new MyRenderer(),
Visible = true
};
compile the method and save the module for the last time. Now you have an darkmode MenuStrip.
To change the ContextMenus style you have to be added the classes from above.
In DnSpy move to the class ServerTree in the RdcMan namespace.
Then move the the method called Init: "internal void Init(Assembly myAssembly)"
In this function we have to add the Renderer to the contextmenu:
Replace this code:
ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Opening += this.OnContextMenu;
this.ContextMenuStrip = contextMenuStrip;
with this code:
ContextMenuStrip contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Renderer = new MyRenderer();
contextMenuStrip.Opening += this.OnContextMenu;
this.ContextMenuStrip = contextMenuStrip;
Then save the method and afterwards save the module. Now are the contextmenus in the ServerTree region in dark mode.
When you right click on the Thumbnail of an connection there is another Contextmenu we have to change.
To set the darkmode for this Contextmenu move to the class "ServerLabel". There is the method called "static ServerLabel()" we will replace this method.
Replace:
static ServerLabel()
{
ServerLabel._menu = new ContextMenuStrip();
ServerLabel._menu.Opening += ServerLabel.MenuPopup;
Button button = new Button
{
FlatStyle = FlatStyle.Flat,
Font = new Font(ServerTree.Instance.Font, FontStyle.Bold)
};
ServerLabel.Height = button.Height;
}
With:
static ServerLabel()
{
ServerLabel._menu = new ContextMenuStrip();
ServerLabel._menu.Renderer = new MyRenderer();
ServerLabel._menu.Opening += ServerLabel.MenuPopup;
ServerLabel.Height = new Button
{
FlatStyle = FlatStyle.Flat,
Font = new Font(ServerTree.Instance.Font, FontStyle.Bold)
}.Height;
}
Save the method and save the Module at the last time under File -> "Save Module...". Now is the main Window of RDCMAN complete in dark Mode.
I have tried in the past to set an dark mode on the different windows in RDCMAN, but the result was very hilarious.
I tried my best to fix it, but after an hour of trying I let it go. Because the most time I'm using RDCMAN is using the RDP connections, so my main goal was it to have an dark mode on the main window. Which should be now fully working.
Please add an dark mode in RDCMAN. I made an approach by myself, to change the colors in the main form:![RDCMAN](https://github.com/MicrosoftDocs/sysinternals/assets/24463981/a00c178b-f35f-463d-b90f-7c3ab28e914c)
I didn't change the contextmenus and the dialog forms, only the main window.
I have set the darkmode colors via DNSPY. The following changes were made:
Class Mainform
Class FormTools
Class ServerTree
Class RdcBaseForm