Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Импорт функции из .exe [D5, Win2k]


Fiend ©   (2004-03-31 15:25:00) 

Здравствуйте Уважаемые!!!

Есть у меня с коллегой общий проект. В нём есть утилита для автоматического обновления. Естественно .exe файл.

Так вот соавтор попросил сделать функцию в этой утилите, с помощью которой можно было запустить "процесс" обновления. Выбрали вариант с экспортом функции потому, что Требуется передать несколько параметров, которые передавать через командную строку не есть гуд.

Функцию сделал, но вот незадача, как только exe загружен LoadLibrary и указатель на ф-цию получен от GetProcAddress, мы ее ессесно вызываем и в отладчике замечаем ужасную картину: на первой же команде происходит AV. Где порыть ума не приложу.

это экспортируемое:
type
 TScript = record
           Size: WORD;
           PScript: PChar;
           end;
 PScript = ^TScript;

function ExternalCall(Script: PScript): boolean; stdcall;
begin
 MainForm:= TMainForm.Create(Application);
 MainForm.UpdateNow(Script);
 MainForm.ShowModal;
 Result:= MainForm.LoadResult=1;
 MainForm.Free;
end;

exports ExternalCall;

а это уже загрузка и выполнение:
type
 TExternalCall = function (Script: PScript): boolean; stdcall;

var hLibrary: THandle;
   fExternalCall: TExternalCall;
   Script: TScript;
   Result: boolean;
begin
 hLibrary:= LoadLibrary('UpdWizard.exe');
 @fExternalCall:= GetProcAddress(hLibrary, 'ExternalCall');
 Script.PScript:= AllocMem(1000);
 StrPCopy(Script.PScript, '/ok/cgi/news.exe?getupdscr&stylea');
 Script.Size:= StrLen(Script.PScript);
 Result:= fExternalCall(@Script);
 FreeLibrary(hLibrary);
 FreeMem(Script.PScript, 1000);
end.

Помогите пожалуйста, хотя бы обсуждением.


Fiend   (2004-03-31 17:18:00) [1]

То Digitman ©   (31.03.04 17:14) [13]
Это всё понятно, но хотелось как всегда с минимальной затратой времени, а вылилось в полдня. Ну да ладно, за-то опыт в обасти экспорта из ехе.

ВСЕМ СПАСИБО!!!
обсуждение закрыто!


Digitman   (2004-03-31 17:14:00) [2]

если два или более приложений желают использовать один и тот же код , есть прямой смысл вынести алгоритм "утилиты обновления" в DLL, и пусть все заинтересованные приложения обращаются к этой ДЛЛ для запуска этого алгоритма ... самый разумный подход ... для того и существует концепция и механизм динамически линкуемых библ-к


Fiend   (2004-03-31 17:07:00) [3]

То Digitman ©   (31.03.04 16:59) [11]
ну да его ессесно не отключишь. про это я забыл.

Я уже "слегка" запутался: какой вариант ты предлагаешь?
1) переделать всё же в ДЛЛ и ее грузить.
2) использвать командную строку.
3) или может что то еще...


Digitman   (2004-03-31 16:59:00) [4]


> отключил из экспортирующего ехе всё


прелюбопытно, что конкретно ... и каким конкретно образом ...

что, код/данные, принадлежащие System.pas, тоже умудрился отключить ?


Digitman   (2004-03-31 16:56:00) [5]


> даже если это assert или beep


assert() использует многие данные из модуля system.pas, раздел initialization которого никто не вызывал

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

ShowMessage('asdasdf') использует модуль Forms, который тоже никто не инициализировал, равно как никто не создавал объект Application, интенсивно используемый этим модулем при манипуляциях с формами

кр.того, ехе м.б. собран с пакетами времени выполнения. которые тоже никто не грузил и не инициализировал


Fiend   (2004-03-31 16:55:00) [6]

Следующим шагом, чтобы проверить слова Digitman`a отключил из экспортирующего ехе всё, и оставил только одну экспортируемую функцию в которой стоит assert
и всё равно АВ не пропал. следовательно, т.к. ничто из VCL не подключено и нет никаких там инициализаций, то дело не в ней.
Но вот в чём непонятно


Fiend   (2004-03-31 16:32:00) [7]

Урезал функции до предела
это экспортируем
function ExternalCall{(Script: PScript)}: boolean; stdcall;
begin
ShowMessage('asdasdf');
{  assert(Application=nil, 'sux');
 MainForm:= TMainForm.Create(nil);
 MainForm.UpdateNow(Script);
 MainForm.ShowModal;
 Result:= MainForm.LoadResult=1;
 MainForm.Free;}
end;

это импортируем
type
 TExternalCall = function {(Script: PScript)}: boolean; stdcall;
Загружаем, получаем адрес, и вызываем:
AV.

Вы меня кажется недопоняли, или невнимательно прочли:
АВ падает сразу на первой команде, даже если это assert или beep

Такое чуйство что толи указатели загруженного PE файла не пересчитаны, то ли даже и не знаю что думать


Digitman   (2004-03-31 16:28:00) [8]


> Application.Initialize первой же строкой?
> Делал, результат тот же.


а кто и когда создал объект Application ?

никто и никогда !

вот тебе и ответ


Digitman   (2004-03-31 16:26:00) [9]


> Fiend


предлагаю не заморачиваться этой идеей, если она хоть как-то использует внутри экспортируемой ф-ции VCL

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


Digitman   (2004-03-31 16:22:00) [10]

попробуй-ка реализовать и экспортировать в exe простую ф-цию

const SomeStr: PChar = 'Hello, World !';
function GetSomeString: PChar;
begin
Result := SomeStr;
end;

и вызвать эту ф-цию после LoadLibrary() и GetProcAddress()

ShowMessage(String(GetSomeString));

и все пройдет на ура !

почему ? да потому что тело импортируемой ф-ции не содержит ни единого обращения ни к одному из внешних и/или неявно инициализируемых (в ходе старта exe-процесса) модулей, т.е. никак не зависит от какого-либо дополнительного/вспомогательного кода/данных ... иными словами - импортируемая ф-ция реализована в теле exe-модуля как 100%-но самодостаточная


Fiend   (2004-03-31 16:18:00) [11]

Что вы предлагаете сделать?
Application.Initialize первой же строкой?
Делал, результат тот же.


Digitman   (2004-03-31 16:14:00) [12]


> Fiend


не смотря на ржание Cobalt'а аки жеребца молодого, он прав
прав в том, что загрузка и/или инициализация требуемых модулей (в т.ч. и в 1-ю очередь - VCL-модулей) происходит при передаче системой управления на точку входа в exe .. что не происходит при LoadLibrary()


Fiend   (2004-03-31 15:53:00) [13]

Я бы не стал так смеяться.
Потому что даже если первой коммандой поставить тривиальнейший Beep(), то всё равно ошибка прямо на нём. Да и в конце концов можно создавать форму указывая nil.

Так что дело не в этом.


Cobalt   (2004-03-31 15:47:00) [14]

ГЫЫЫЫ :))))
А Application кто будет инициализировать????
Это же объект - в ЕХЕ-ке загруженном, а не в вашем, вызывающем.

Общая рекомендация - отделяйте "бизнес-логику" (деловую логику) от интерфейса!!!


Наверх

Титульная страница Поиск, карта сайта Написать письмо