Skip to content

Commit

Permalink
Merge pull request #47 from Guila767/master
Browse files Browse the repository at this point in the history
Added support for menu icons
  • Loading branch information
ZehMatt authored Nov 22, 2021
2 parents 77ac496 + 9db398b commit 3ad45bc
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 19 deletions.
2 changes: 2 additions & 0 deletions src/Bindings/Bindings.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
<UseWindowsForms>true</UseWindowsForms>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
Expand All @@ -17,6 +18,7 @@
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WindowsForms" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
Expand Down
2 changes: 1 addition & 1 deletion src/Bindings/Plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifdef _WIN64
#ifdef _WIN64
#pragma comment(lib, "pluginsdk/x64dbg.lib")
#pragma comment(lib, "pluginsdk/x64bridge.lib")
#pragma comment(lib, "pluginsdk/DeviceNameResolver/DeviceNameResolver_x64.lib")
Expand Down
97 changes: 97 additions & 0 deletions src/Bindings/UI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "Marshal.hpp"

#pragma comment(lib, "Gdi32.lib")

using namespace System;
using namespace System::Runtime::InteropServices;

Expand Down Expand Up @@ -154,6 +156,34 @@ namespace Dotx64Dbg::Native
return _plugin_menuadd(parent, cstr);
}

static bool SetIcon(int hMenu, System::Drawing::Image^ image)
{
auto data = GetIconData(image);

ICONDATA icon{ 0 };
icon.data = &data[0];
if (icon.size = data.size(); !icon.size)
return false;

_plugin_menuseticon(hMenu, &icon);

return true;
}

static bool SetEntryIcon(int hPlugin, int hEntry, System::Drawing::Image^ image)
{
auto data = GetIconData(image);

ICONDATA icon{ 0 };
icon.data = &data[0];
if (icon.size = data.size(); !icon.size)
return false;

_plugin_menuentryseticon(hPlugin, hEntry, &icon);

return true;
}

static bool AddEntry(int parent, int id, System::String^ name)
{
msclr::interop::marshal_context oMarshalContext;
Expand All @@ -177,6 +207,73 @@ namespace Dotx64Dbg::Native
{
return _plugin_menuremove(id);
}

private:

static std::vector<uint8_t> GetIconData(_In_ System::Drawing::Image^ image)
{
System::Drawing::Bitmap bitmap(image);
bitmap.MakeTransparent();
HBITMAP hBitmap = (HBITMAP)bitmap.GetHbitmap().ToPointer(); // Used only for bitmap info

BITMAP bmp{ 0 };
if (!GetObject(hBitmap, sizeof(BITMAP), &bmp))
return {};

LONG pixelArraySize = bmp.bmWidthBytes * bmp.bmHeight;
const size_t bitmapSize = pixelArraySize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV5HEADER);
auto bitmapData = std::vector<uint8_t>(bitmapSize);

BITMAPFILEHEADER bmfh{ 0 };
bmfh.bfType = 0x4D42;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPV5HEADER);
bmfh.bfSize = (DWORD)bitmapSize;

BITMAPV5HEADER bmh{ 0 };
bmh.bV5Size = sizeof(BITMAPV5HEADER);
bmh.bV5Width = bmp.bmWidth;
bmh.bV5Height = -bmp.bmHeight;
bmh.bV5Planes = 1;
bmh.bV5BitCount = bmp.bmBitsPixel;
bmh.bV5Compression = BI_RGB | BI_BITFIELDS,
bmh.bV5RedMask = 0xFF << 16;
bmh.bV5GreenMask = 0xFF << 8;
bmh.bV5BlueMask = 0xFF;
bmh.bV5AlphaMask = 0xFF << 24;
bmh.bV5SizeImage = pixelArraySize;
bmh.bV5XPelsPerMeter = 0;
bmh.bV5YPelsPerMeter = 0;
bmh.bV5CSType = LCS_sRGB;
bmh.bV5Intent = LCS_GM_GRAPHICS;

/*
Don't get the DI bitmap bits from a handle retrieved by 'Bitmap::GetHbitmap()' because the alpha channel gets destroy.
For this, use the Gdiplus functions like 'LockBits' for retrieving the bitmap data.
Note: Functions and classes fom 'System::Drawing' are pretty much wrappers for Gdiplus
*/
System::Drawing::Rectangle regionRect(0, 0, bmp.bmWidth, bmp.bmHeight);
auto bmpData = bitmap.LockBits(regionRect, System::Drawing::Imaging::ImageLockMode::ReadOnly, System::Drawing::Imaging::PixelFormat::Format32bppArgb);
void* bmpBits = bmpData->Scan0.ToPointer();
// pixel array
memcpy_s(
&bitmapData[bmfh.bfOffBits],
bitmapSize - bmfh.bfOffBits,
bmpBits,
pixelArraySize
);
bitmap.UnlockBits(bmpData);
// bmp file header
memcpy_s(&bitmapData[0], bitmapSize, &bmfh, sizeof(BITMAPFILEHEADER));
// bmp v5 header
memcpy_s(
&bitmapData[sizeof(BITMAPFILEHEADER)],
bitmapSize - sizeof(BITMAPFILEHEADER),
&bmh,
sizeof(BITMAPV5HEADER)
);

return bitmapData;
}
};

static System::String^ InputPrompt(System::String^ title)
Expand Down
7 changes: 5 additions & 2 deletions src/Dotx64Managed/Menus.Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ internal static void CreateNewPlugin()

internal static void InitializeMainMenu()
{
AddMenu("Main/Run Script", RunScript);
AddMenu("Main/Create Plugin", CreateNewPlugin);
// Plugin icon
Native.UI.Menu.SetIcon(MainMenu, Properties.Resources.Dotx64DbgIcon);

AddMenu("Main/Run Script", Properties.Resources.RunIcon, RunScript);
AddMenu("Main/Create Plugin", Properties.Resources.NewScriptIcon, CreateNewPlugin);
AddSeperator("Main");
}

Expand Down
16 changes: 11 additions & 5 deletions src/Dotx64Managed/Menus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,16 @@ internal static void HandleCallback(int id)
}
}

internal static void AddMenu(string path, UI.Menu.MenuDelegate func)
{
AddMenu(null, path, func);
}
internal static void AddMenu(string path, UI.Menu.MenuDelegate func) =>
AddMenu(path, null, func);

internal static void AddMenu(string path, System.Drawing.Image image, UI.Menu.MenuDelegate func) =>
AddMenu(null, path, image, func);

internal static void AddMenu(Plugin plugin, string path, UI.Menu.MenuDelegate func) =>
AddMenu(plugin, path, null, func);

internal static void AddMenu(Plugin plugin, string path, UI.Menu.MenuDelegate func)
internal static void AddMenu(Plugin plugin, string path, System.Drawing.Image image, UI.Menu.MenuDelegate func)
{
var pos = 0;
var prev = 0;
Expand Down Expand Up @@ -134,6 +138,8 @@ internal static void AddMenu(Plugin plugin, string path, UI.Menu.MenuDelegate fu

entryName = path.Substring(prev);
Native.UI.Menu.AddEntry(nextEntry.parent, nextEntry.id, entryName);
if (image is not null)
Native.UI.Menu.SetEntryIcon(Manager.PluginHandle, nextEntry.id, image);

NextInternalId++;
}
Expand Down
18 changes: 9 additions & 9 deletions src/Dotx64Managed/Plugins.DependencyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,25 @@ public DependencyResolver()
pluginDepsCache = new();
}

public string[] ResolvePluginDepencies(Plugin plugin, CancellationToken cancellationToken)
public string[] ResolvePluginDependencies(Plugin plugin, CancellationToken cancellationToken)
{
if (plugin.Info.Dependencies is null || plugin.Info!.Dependencies.Length == 0)
return Array.Empty<string>();

if (!HasDependenciesChanged(plugin))
return pluginDepsCache[plugin.GetHashCode()].cachedResolvedDependencies;
string[] deps = GetPluginDepencies(plugin, cancellationToken);
string[] deps = GetPluginDependencies(plugin, cancellationToken);

AddPluginToCache(plugin, deps);

return deps;
}

public string[] ResolvePluginDepencies(string pluginPath) => throw new NotImplementedException();
public string[] ResolvePluginDependencies(string pluginPath) => throw new NotImplementedException();

protected abstract string[] GetPluginDepencies(Plugin plugin, CancellationToken cancellationToken);
protected abstract string[] GetPluginDependencies(Plugin plugin, CancellationToken cancellationToken);

private static int GetDepenciesHash(Plugin plugin)
private static int GetDependenciesHash(Plugin plugin)
{
int hash = 0;
foreach (var p in plugin.Info.Dependencies)
Expand All @@ -58,7 +58,7 @@ private static int GetDepenciesHash(Plugin plugin)
private bool HasDependenciesChanged(Plugin plugin)
{
int pluginInstanceHash = plugin.GetHashCode();
int currentDepsHash = GetDepenciesHash(plugin);
int currentDepsHash = GetDependenciesHash(plugin);
if (!pluginDepsCache.TryGetValue(pluginInstanceHash, out var cache))
{
return true;
Expand All @@ -69,7 +69,7 @@ private bool HasDependenciesChanged(Plugin plugin)
private void AddPluginToCache(Plugin plugin, string[] resolvedDepencies)
{
int pluginInstanceHash = plugin.GetHashCode();
int currentDepsHash = GetDepenciesHash(plugin);
int currentDepsHash = GetDependenciesHash(plugin);
pluginDepsCache[pluginInstanceHash] = (currentDepsHash, resolvedDepencies);
}

Expand Down Expand Up @@ -121,7 +121,7 @@ public NuGetDependencyResolver()
Logger = new NuGetDependencyResolverLogger(Console.Out);
}

protected override string[] GetPluginDepencies(Plugin plugin, CancellationToken cancellationToken)
protected override string[] GetPluginDependencies(Plugin plugin, CancellationToken cancellationToken)
{
if (plugin.Info is null)
return Array.Empty<string>();
Expand Down Expand Up @@ -427,7 +427,7 @@ internal static class DependencyResolverExtensions
{
public static string[] ResolveDependencies(this Plugin plugin, Plugins.DependencyResolver resolver, CancellationToken token)
{
return resolver.ResolvePluginDepencies(plugin, token);
return resolver.ResolvePluginDependencies(plugin, token);
}

public static string[] ResolveDependencies(this Plugin plugin, Plugins.DependencyResolver resolver) =>
Expand Down
34 changes: 32 additions & 2 deletions src/Dotx64Managed/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/Dotx64Managed/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,19 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Dotx64DbgIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Dotx64DbgIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="NewScriptIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NewScript.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="plugin_cs" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Template\plugin.cs;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="plugin_json" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Template\plugin.json;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
</data>
<data name="RunIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Run.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>
Binary file added src/Dotx64Managed/Resources/Dotx64DbgIcon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Dotx64Managed/Resources/NewScript.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/Dotx64Managed/Resources/Run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 3ad45bc

Please sign in to comment.