Замечания и предложения

А куда вы записываете поток ресурса?

Немного изменил код и получил точное описание ошибки: поток имеет значение null. Библиотека:

library MyLib;
{$Resource 'Без названия (2).png'}
{$Reference 'System.Drawing.dll'}
{$Reference 'System.dll'}
{$Reference 'System.IO.dll'}
Uses System;
Uses System.IO;
Uses System.Drawing;
function GetBMP(): System.Drawing.Bitmap;
begin
  Result := new System.Drawing.Bitmap(System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream('Без названия (2).png'));
end;
End.

Программа:

{$Reference 'MyLib.dll'}
{$Reference 'System.Windows.Forms.dll'}
{$Reference 'System.Drawing.dll'}
{$Reference 'System.dll'}
begin
  var MainImage := MyLib.GetBMP();
  var MainForm := new System.Windows.Forms.Form;
  MainForm.ClientSize := MainImage.Size;
  MainForm.BackgroundImage := MainImage;
  System.Windows.Forms.Application.Run(MainForm);
end.

Исключение было вызвано в библиотеке из конструктора класса Bitmap. Текст: “MyLib.pas(11) : Ошибка времени выполнения: Значение ‘null’ недопустимо для ‘stream’.”.

Да я тоже у себя попробовал, не работает только в библиотеках. Кстати System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream вроде можно заменить на GetResourceStream. А анализатор кода в основной программе с подключённой библиотекой сходит с ума, его вообще проверяли?

Заменить можно, но я теперь практикую PABCSystem’о-замещение.:sunglasses:

А вот анализатор кода мне “открыл Америку”! Оказывается, что можно создавать экземпляры целых пространств имён! Пространственно-ориентированное программирование против объектно-ориентированного!

Ну тогда напишите свою GetResourceStream и вставляйте в каждую программу потому что такие длинные строчки надо стараться избегать. А вообще байкот дело тупое. Пока на горизонте не видно и близко отключения PABCSystem - это лишь трата времени и сил.

Я тут кое-что проверил. Короче, если ресурс определён в библиотеке, то программа крашится, а вот если ресурс определён в основной программе, то даже вызывая его из библиотеки, он нормально отрабатывает.

Программа:

{$reference 'md.dll'}
{$reference 'system.dll'}
{$reference 'system.drawing.dll'}
{$reference 'system.windows.forms.dll'}
{$resource 'Img.png'}

uses
   System,
      System.Drawing,
      System.Windows.Forms;

begin

   var MainForm: System.Windows.Forms.Form := new Form();
   MainForm.ClientSize := new Size(1280, 800);
   MainForm.BackgroundImage := md.md.getImageFromResource();
   System.Windows.Forms.Application.Run(MainForm);

end.

DLL:


{$reference 'System.dll'}
{$reference 'System.Drawing.dll'}

LIBRARY md;

interface

   uses
      System,
         System.Drawing;

   {$resource 'Img.png'}
   
   function getImageFromResource(): System.Drawing.Image;
   
implementation

   function getImageFromResource(): System.Drawing.Image;
      begin //1a
      
         Result := Image.FromStream(getResourceStream('Img.png'));
      
      end; //1a

end.

Возможно тогда System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream не подходит и чтоб вытащить ресурсы из dll надо другую функцию? Ну то есть для основной программы и модулей информация в GetEntryAssembly а у dll файлов она отдельно? Поищите, у меня ещё не так много места в голове освободилось для изучения System.Reflection.Assembly ;).

Это я тоже заметил, но ведь ресурс должен быть именно в библиотеке!

Может быть, но в платформе .NET, по сути, различий между Dll, Exe и WinExe практически нет. Все откомпилированные результаты называются сборками. Тут, думаю, лучше спросить у Админа.

Я всё же залез в асембли и оказался прав, вот dll:

library Lib;
{$Resource 'im.png'}
{$Reference 'System.Drawing.dll'}
{$Reference 'System.dll'}
{$Reference 'System.IO.dll'}
Uses System;
Uses System.IO;
Uses System.Drawing;

function GetBMP(): System.Drawing.Bitmap;
begin
  Result := new System.Drawing.Bitmap(System.Reflection.Assembly.GetExecutingAssembly.GetManifestResourceStream('im.png'));
end;
End.

При чём тут отличия, я говорю про то что это 2 разных хранилища подпрограмм и типов. И GetResourceStream пытается найти точку начала потока в exe файле а не в dll.

2 лайка

Спасибо большое! Очень выручили!

Да, я перепутал…

Таак, запись в блокнотике: взять на заметку при сборке .DLL с ресурсами :slight_smile:

У Sequence of T есть функция Reverse без параметров. У List<T> тоже. Мне понадобилась функция List<T>.Reverse, но всегда вызывается первая. Мне казалось функцию должно подобрать по возвращаемому значению, но l := l.Reverse, где l:List<T> не работает.

Здравствуйте. Можно ли реализовать отображение стека вызова подпрограмм (процедур и функций). И показать там значение переменных и т.д. Что поможет отлаживать программы. Данная идея возникла при объяснении детям темы “рекурсия”, и если бы этот функционал был - было бы проще не только преподавателям, но и ученикам отлаживать программы. Заранее Большое Спасибо!!!)

Во вкладке вид есть меню Локальные переменные, вам это нужно?

Было бы не плохо, если бы вы добавили кнопку (или сочетание клавиш) быстрого сворачивания всего кода, а то как-то не очень айс сворачивать каждый метод и каждую функцию (Весь раздел сворачивать не надо!).

Стек вызовов позволяет подняться по вызовам наверх и посмотреть, к примеру, состояние локальных переменных, которые находятся в функциях, вызвавших ту, в которой мы стоим. Стандартная функциональность для любой IDE, к слову. Окошко “Локальные переменные” ее заменить не может.

суть (цифры - адреса положения инструкций в секции кода):

0: procedure p1();
1: begin
2:    var t1 := 1; //а сюда мы можем взглянуть с помощью стека вызовов
3:    p2();
4: end;
5: 
6: procedure p2();
7: begin
8:    var t2 := 2; // тут брейкпойнт
9: end;
...
100: p1();
...

Это возможно потому, что точки входа в функции кладутся на стек последовательно, и находятся в пределах известной и доступной памяти в любой момент исполнения. В данном случае (грубо):

...
[p1_parameters {нет}]
[return_address_to_p1_caller {100}]
[p1_local_variables {t1}]
[p2_parameters {нет}]
[return_address_to_p1 {3}]
[p2_local_variables {t2}] << вершина стека

Возможно, в точной очереди расположения параметров, адреса возврата, и переменных я не прав, но это схема. Гуглить было лень.

1 лайк

Да, это я видел, но если функция вызывается из другой функции или из самой себя, в этой вкладке видны только переменные текущей функции (где сейчас находится отладка). А хотелось бы видеть и значения переменных для функций которые привели к вызову текущей. Например программа:

procedure f(n:integer); begin _ if (n = 0) then exit;_ _ write(n,’ ');_ _ f(n - 1);_ end; begin _ f(3);_ end.

Хотелось бы видеть на момент отладки, когда n=0, т.е. процедура f была вызвана четвёртый раз что то подобное: 1) f(n = 3) 2) f(n = 2) 3 f(n = 1) 4 f(n = 0) То есть весь стек вызовов подпрограмм со значением входных и локальных переменных на текущий момент отладки. Большое спасибо за ответ!

В PABCSystem на строчках 3403, 4187, 4194 при создании списка или словаря надо задавать ему начальный размер, это влияет на производительность.

Ну тогда могу посоветовать на данном этапе использовать отладку “Шаг со входом в подпрограмму”, тогда в окне “Локальные переменные” вы сможете отслеживать стек на каждом шаге.