Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: avc от 25-10-2020, 18:36:49

Название: Где взять стандартные иконки команд
Отправлено: avc от 25-10-2020, 18:36:49
Кто-нибудь знает из какой ресурсной dll Автокад грузит иконки для стандартных команд? Хочу задействовать их на своих панелях. Перебрал все dll в папке Автокад - нет там почти никаких картинок из интерфейса Автокада и иконок команд тоже не вижу. Понятно что можно пытаться сделать свои похожие иконки, выдернуть с экрана или экспортировать из диалога CUI. Но в следующей версии опять поменяют иконки надо будет начинать с начала. Есть путь по проще?
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 25-10-2020, 20:41:38
Поизучай файлы acadbtn.xmx и acadbtn_light.xmx (это для светлой темы)
Название: Re: Где взять стандартные иконки команд
Отправлено: avc от 25-10-2020, 21:18:50
Первым делом полез в эти файлы. Там текстом прописаны цвета темы - тоже полезная вещь. Но до конца долистать я не догадался. А в конце там строки вида
Код - XML [Выбрать]
  1. <String name="VScrollBarAddLine" value=":/VScrollBar_AddLine.png"/>

Но это не то. Это описание мелких элементов интерфейса, а не команд и объектов чертежа. И даже для этих элементов эти png у меня на всем системном диске не находятся. То есть они тоже к каких-то ресурсах/архивах запакованы.
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 25-10-2020, 21:28:57
avc,
Плохо ты искал. И подход у тебя .NET-чика. А ресурсы там как в обычной native dll:
(https://live.staticflickr.com/65535/50529578892_6a03be098e_o.jpg)
Для AutoCAD 2021 всего там 3202 иконки.
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 25-10-2020, 21:40:30
Вот эта статейка тебе может помочь:
http://dedjo.blogspot.com/2008/01/how-to-load-unmanaged-native-resources.html
Ну и это в дополнение:
https://stackoverflow.com/questions/45624557/c-sharp-extract-resource-from-native-pe
Название: Re: Где взять стандартные иконки команд
Отправлено: avc от 25-10-2020, 23:35:42
Извиняюсь, не туда смотрел. Я полез в папку Themes и там изучал DarkTheme.xbel.
Конечно xmx я не догадался попытаться открыть, да и если б попытался - VS показывает его как двоичный файл, не видит ресурсов.
Что ресурсы бываю какие-то разные - я и не в курсе. Спасибо за ссылочки, теперь разберусь.
А что внутри этих ресурсов? Resource Hacker просто как двоичные данные показывает. И я в них не вижу заголовка PNG. и на BMP большинство не похожи. Первые символы в основном II* Что это?
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 25-10-2020, 23:46:21
А что внутри этих ресурсов?
.ico
Название: Re: Где взять стандартные иконки команд
Отправлено: avc от 26-10-2020, 16:11:59
Что-то не получается.
Код - C# [Выбрать]
  1.  internal static class ResourceManager
  2.   {
  3.     [DllImport("kernel32.dll", SetLastError = true)]
  4.     public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
  5.  
  6.     [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  7.     public static extern IntPtr LoadLibrary(string lpFileName);
  8.  
  9.     [DllImport("kernel32.dll", SetLastError = true)]
  10.     public static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
  11.  
  12.     [DllImport("kernel32.dll", SetLastError = true)]
  13.     public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
  14.  
  15.     [DllImport("kernel32.dll", SetLastError = true)]
  16.     public static extern IntPtr LockResource(IntPtr hResData);
  17.  
  18.     [DllImport("kernel32.dll", SetLastError = true)]
  19.     public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
  20.  
  21.     internal static Icon GetIcon(string lpFileName, string lpName, string lpType)
  22.     {
  23.       IntPtr hModule = LoadLibrary(lpFileName);
  24.       if (hModule == IntPtr.Zero) return null;
  25.       IntPtr hResource = FindResource(hModule, lpName, lpType);
  26.       if (hResource == IntPtr.Zero) return null;
  27.       uint resSize = SizeofResource(hModule, hResource);
  28.       IntPtr resData = LoadResource(hModule, hResource);
  29.       if (resData == IntPtr.Zero) return null;
  30.       byte[] uiBytes = new byte[resSize];
  31.       IntPtr ipMemorySource = LockResource(resData);
  32.       Marshal.Copy(ipMemorySource, uiBytes, 0, (int)resSize);
  33.       using MemoryStream m = new MemoryStream(uiBytes);
  34.       return new Icon(m);
  35.     }
  36.  
  37.     internal static void SaveIcon(string lpFileName, string lpName, string lpType, string toFolder)
  38.     {
  39.       Icon ico = GetIcon(lpFileName, lpName, lpType);
  40.       if (ico == null) return;
  41.       using FileStream file = File.Create(Path.Combine(toFolder, lpName) + ".ico");
  42.       ico.Save(file);
  43.     }
и для теста
Код - C# [Выбрать]
  1.     [CommandMethod("IconTest")]
  2.     public static void IconTestCommand()
  3.     {
  4.       ResourceManager.SaveIcon(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  5.       "RCDATA_16_2DOPTIM",
  6.       "RCData",
  7.       @"Z:\test"
  8.       );
  9.     }

Библиотека подгружается. Но FindResource всегда возвращает 0
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 26-10-2020, 17:11:24
Ну не так всё просто. :) Это тебе не на C# писать... :D

Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.Runtime;
  2. using System;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5.  
  6. // This line is not mandatory, but improves loading performances
  7. [assembly: CommandClass(typeof(GetIconFromAcadXMX.MyCommands))]
  8.  
  9. namespace GetIconFromAcadXMX
  10. {
  11.   static class NativeResourceManager
  12.   {
  13.     public const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002;
  14.     public const uint LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020;
  15.     public static IntPtr RC_RCDATA = (IntPtr)((UInt16)10);
  16.  
  17.     [DllImport("kernel32.dll", SetLastError = true)]
  18.     public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
  19.  
  20.     [DllImport("Kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  21.     public static extern IntPtr LoadLibrary(string lpFileName);
  22.  
  23.     [DllImport("kernel32.dll", SetLastError = true)]
  24.     public static extern IntPtr FindResource(IntPtr hModule, string lpName, IntPtr lpType);
  25.  
  26.     [DllImport("kernel32.dll", SetLastError = true)]
  27.     public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
  28.  
  29.     [DllImport("kernel32.dll", SetLastError = true)]
  30.     public static extern IntPtr LockResource(IntPtr hResData);
  31.  
  32.     [DllImport("kernel32.dll", SetLastError = true)]
  33.     public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
  34.  
  35.     public static MemoryStream GetIcon(string lpFileName, string lpName, IntPtr lpType)
  36.     {
  37.       IntPtr hModule = LoadLibraryEx(lpFileName, IntPtr.Zero,
  38.         LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
  39.       if (hModule == IntPtr.Zero) return null;
  40.       IntPtr hResource = FindResource(hModule, lpName, lpType);
  41.       if (hResource == IntPtr.Zero) return null;
  42.       uint resSize = SizeofResource(hModule, hResource);
  43.       IntPtr resData = LoadResource(hModule, hResource);
  44.       if (resData == IntPtr.Zero) return null;
  45.       byte[] uiBytes = new byte[resSize];
  46.       IntPtr ipMemorySource = LockResource(resData);
  47.       Marshal.Copy(ipMemorySource, uiBytes, 0, (int)resSize);
  48.       return new MemoryStream(uiBytes);
  49.     }
  50.  
  51.     public static void SaveIcon(string lpFileName, string lpName, IntPtr lpType, string toFolder)
  52.     {
  53.       using (MemoryStream ico = GetIcon(lpFileName, lpName, lpType)) {
  54.         if (ico == null) return;
  55.         using (FileStream file = File.Create(Path.Combine(toFolder, lpName) + ".ico"))
  56.           file.Write(ico.ToArray(),0, (int)ico.Length);
  57.       }
  58.     }
  59.   }
  60.   public class MyCommands
  61.   {
  62.     [CommandMethod("IconTest")]
  63.     public static void IconTestCommand()
  64.     {
  65.       NativeResourceManager.SaveIcon(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  66.       "RCDATA_16_2DOPTIM",
  67.       NativeResourceManager.RC_RCDATA,
  68.       @"Z:\test"
  69.       );
  70.     }
  71.   }
  72. }
  73.  
Название: Re: Где взять стандартные иконки команд
Отправлено: avc от 26-10-2020, 21:00:02
Я так и думал, что надо тип ресурса цифрой передать как во всех остальных примерах. Но нигде не мог найти значение этой константы RC_RCDATA. Спасибо!
Но! Иконок в этой библиотеке нет. Создать Icon на этих данных невозможно. Зато эти данные прекрасно считывает Bitmap. И оказалось, что большинство картинок - это TIFы. II* - это заголовок TIF. А вот с остальными не очень понятно. Bitmap сообщает, что RawFormat == Ico, но при этом сохраняет в PNG с переконвертацией (вижу, что внутри файла уже не то содержимое). Но вобщем-то это все уже не имеет значние, потому что Bitmap можно присвоить почти любому контролу WinForm, не зависимо от содержимого (надеюсь, что независимо. еще не проверял)
Код - C# [Выбрать]
  1.     static Bitmap GetBitmap(string lpFileName, string lpName, IntPtr lpType)
  2.     {
  3.       IntPtr hModule = LoadLibrary(lpFileName);
  4.       if (hModule == IntPtr.Zero) return null;
  5.       IntPtr hResource = FindResource(hModule, lpName, lpType);
  6.       if (hResource == IntPtr.Zero) return null;
  7.       uint resSize = SizeofResource(hModule, hResource);
  8.       IntPtr resData = LoadResource(hModule, hResource);
  9.       if (resData == IntPtr.Zero) return null;
  10.       byte[] uiBytes = new byte[resSize];
  11.       IntPtr ipMemorySource = LockResource(resData);
  12.       Marshal.Copy(ipMemorySource, uiBytes, 0, (int)resSize);
  13.       using MemoryStream m = new MemoryStream(uiBytes);
  14.       return new Bitmap(m);
  15.     }
  16.  
  17.     internal static void SaveBitmap(string lpFileName, string lpName, IntPtr lpType, string toFolder)
  18.     {
  19.       Bitmap bmp = GetBitmap(lpFileName, lpName, lpType);
  20.       if (bmp == null) return;
  21.       Guid format = bmp.RawFormat.Guid;
  22.       string ext =
  23.         format == ImageFormat.Png.Guid ? "png" :
  24.         format == ImageFormat.Gif.Guid ? "gif" :
  25.         format == ImageFormat.Tiff.Guid ? "tif" :
  26.         format == ImageFormat.Jpeg.Guid ? "jpg":
  27.         format == ImageFormat.Icon.Guid ? "ico":
  28.         format == ImageFormat.Wmf.Guid ? "wmf":
  29.         format == ImageFormat.Exif.Guid ? "exif":
  30.         "bmp";
  31.       bmp.Save($"{toFolder}\\{lpName}.{ext}");
  32.     }

Код - C# [Выбрать]
  1.     [CommandMethod("IconTest")]
  2.     public static void IconTestCommand()
  3.     {
  4.       ResourceManager.SaveBitmap(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  5.       "IDB_TBAR_SMILEY",   ResourceManager.RC_RCDATA,  @"Z:\test" );
  6.       ResourceManager.SaveBitmap(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  7.       "RCDATA_16_2DOPTIM", ResourceManager.RC_RCDATA, @"Z:\test");
  8.       ResourceManager.SaveBitmap(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  9.       "RCDATA_16_2DSTEERINGWHEEL", ResourceManager.RC_RCDATA, @"Z:\test");
  10.       ResourceManager.SaveBitmap(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  11.       "RCDATA_16_3DALIGN", ResourceManager.RC_RCDATA, @"Z:\test");
  12.       ResourceManager.SaveBitmap(@"c:\Program Files\Autodesk\AutoCAD 2021\acadbtn.xmx",
  13.       "RCDATA_16_3DARRAY", ResourceManager.RC_RCDATA, @"Z:\test");
  14.     }
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 26-10-2020, 21:05:25
Иконок в этой библиотеке нет.
Это не те иконки. Я же сказал, что каждый из этих ресурсов - это .ico-файл. Описание этого формата:
https://ru.wikipedia.org/wiki/ICO_(формат_файла) (https://ru.wikipedia.org/wiki/ICO_(формат_файла))
https://en.wikipedia.org/wiki/ICO_(file_format) (https://en.wikipedia.org/wiki/ICO_(file_format))
Английское описание полнее.
Название: Re: Где взять стандартные иконки команд
Отправлено: Дмитрий Загорулькин от 27-10-2020, 17:45:30
Понятно что можно пытаться сделать свои похожие иконки, выдернуть с экрана или экспортировать из диалога CUI.
Что-то мне начинает казаться, что этот способ проще )
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 27-10-2020, 17:47:54
Что-то мне начинает казаться, что этот способ проще )
Это если парочку. А если все 3202???
Название: Re: Где взять стандартные иконки команд
Отправлено: avc от 27-10-2020, 18:00:30
Что-то мне начинает казаться, что этот способ проще )
Неее. Восстанавливать прозрачность на иконках - то еще развлечение. А процедурка получилась простенькая - обычное обращение к Win32. Осталось оформить с поиском текущей папки Автокад. Можно даже сделать с учетом светлой/темной темы.
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 27-10-2020, 18:06:55
Осталось оформить с поиском текущей папки Автокад.
Ты имеешь в виду каталог с acad.exe? Из своего плагина, загруженного внутрь AutoCAD?
Как вариант:
Код - C# [Выбрать]
  1. System.Windows.Forms.Application.ExecutablePath;
Или
Код - C# [Выбрать]
  1. AppDomain.CurrentDomain.BaseDirectory();
Название: Re: Где взять стандартные иконки команд
Отправлено: avc от 27-10-2020, 19:13:44
Вот так работает:
Код - C# [Выбрать]
  1.    
  2.     internal static bool DarkTheme
  3.     {
  4.       get => AcadApp.Version.Major >= 20 && (short)AcadApp.GetSystemVariable("COLORTHEME") == 0;
  5.     }
  6.  
  7.     internal static Bitmap BuiltinBitmap(string Name)
  8.     {
  9.       string lib = AcadApp.Version.Major < 20 || DarkTheme ? "acadbtn.xmx" : "acadbtn_light.xmx";
  10.       string filename = System.Windows.Forms.Application.ExecutablePath.Replace("acad.exe", lib);
  11.       return ResourceManager.GetBitmap(filename, Name, ResourceManager.RC_RCDATA);
  12.     }
  13.  
  14. [CommandMethod("IconTest")]
  15.     public static void IconTestCommand()
  16.     {
  17.       Document doc = AcadApp.DocumentManager.MdiActiveDocument;
  18.       Editor ed = doc.Editor;
  19.       PromptStringOptions pso = new PromptStringOptions("Image name? "){
  20.        AllowSpaces = false, DefaultValue = "RCDATA_16_ABOUT" };
  21.       PromptResult pr = ed.GetString(pso);
  22.       if (pr.Status != PromptStatus.OK) return;
  23.       Bitmap bmp = BuiltinBitmap(pr.StringResult);
  24.       if (bmp == null)
  25.       {
  26.         ed.WriteMessage("\nBitmap not loaded\n");
  27.         return;
  28.       }
  29.       using Form f = new Form() {
  30.         Name = "Test",
  31.         Text = "Test",
  32.         MinimumSize = new Size(32, 32),
  33.         FormBorderStyle = FormBorderStyle.SizableToolWindow };
  34.       PictureBox box = new PictureBox() {
  35.         Name = "box",
  36.         Dock = DockStyle.Fill,  
  37.         SizeMode = PictureBoxSizeMode.CenterImage,
  38.         Image = bmp  };
  39.       f.Controls.Add(box);
  40.       f.ShowDialog();
  41.     }
Название: Re: Где взять стандартные иконки команд
Отправлено: Александр Ривилис от 04-11-2020, 14:20:28
avc,
Оказывается можно еще проще:
Код - C# [Выбрать]
  1. System.Drawing.Icon ico = Autodesk.AutoCAD.Internal.Utils.GetAcadResourceIcon("имя ресурса");
Для проверки:
Код - C# [Выбрать]
  1. public void GetIconWithId() // This method can have any name
  2. {
  3.   Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  4.   Editor ed = doc.Editor;
  5.   System.Drawing.Icon ico = Autodesk.AutoCAD.Internal.Utils.GetAcadResourceIcon("RCDATA_32_BLOCK");
  6.   ed.WriteMessage("Icon size = {0}", ico.Size);
  7.   using (System.Windows.Forms.Form f = new System.Windows.Forms.Form()
  8.   {
  9.     Name = "Test", Text = "Test",
  10.     MinimumSize = new System.Drawing.Size(32, 32),
  11.     FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow
  12.   })
  13.   {
  14.     System.Windows.Forms.PictureBox box = new System.Windows.Forms.PictureBox()
  15.     {
  16.       Name = "box",
  17.       Dock = System.Windows.Forms.DockStyle.Fill,
  18.       SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage,
  19.       Image = ico.ToBitmap()
  20.     };
  21.     f.Controls.Add(box);
  22.     f.ShowDialog();
  23.   }
  24. }