<
  • Главная
Статьи

TUnRar без DLL


Дмитро Мозулёв
дата публікації 28-11-2006 7:43

Добрий день. Перед вами моя перша стаття. У ній розглядаються відразу два важливих питання: "Як програмно розпаковувати * .rar архіви" і "Що зробити, щоб не тягати * .dll бібліотеки за своїм додатком". Обидві теми заслуговують окремої розмови. Почати пропоную з першої.

Давним-давно, на початку 90-х, будучи студентом Челябінського Технічного Університету (спеціальність ЕОМ), Євген Рошал (майбутній автор "WinRar" і "FAR") вирішив створити архіватор. Перші спроби успіхом не увінчалися, проект простоював понад рік. Першу нормальну версію архіватора RAR 0.1 (припускаю, абревіатура "RAR" - це "Roshal ARchive") в березні 1993 року Євген ризикнув показати кільком знайомим. Архіватор стрімко розвивався і, вже восени того ж року, версія 1.3 (не без допомоги Андрія Спасібожко) пішла в маси. Сьогодні WinRar - найпопулярніший архіватор. Про те, як програмно розпаковувати такі архіви в Delphi, нам і належить сьогодні поговорити.

Пригадую, як кілька років тому був шалено радий, коли випадково в відомих "Радах по Delphi від Валентина Озерова" натрапив на розділ "Створюємо власний UnRar, використовуючи unrar.dll". Цілий день я мучився, опрацьовуючи наведений лістинг (потім до речі, де тільки не натикався на листинги "один в один"; дивіться тут ). Скінчилося все тим, що розплювався, статут коментувати "зайві" рядки, засмутившись від численних помилок доступу до пам'яті, закинув проект на кілька років ...

Ну, до суті. Програмно розпакувати * .rar архіви можна двома способами:

  1. викликати WinRar.exe з командного рядка з відповідними ключами
  2. скористатися API функціями бібліотеки "UnRar.dll"

Перший спосіб я описувати не буду (бо не знаю), мова піде про другий. Бібліотеку "unrar.dll" можна знайти в папці, в яку встановлений WinRar або в архіві, який додається до статті. Для того щоб додаток могло працювати з цією бібліотекою, dll повинна розташовуватися або в одній папці з exe, або в системній папці Windows.

Напишемо ми багато. Зведеться, правда, все до однієї процедури UnRarFile, перший аргумент якої - rar-файл, другий - результуюча директорія [яку можна і не вказувати]:

procedure UnRarFile (RarFileName: string; Directory: string = '');

Відразу обмовлюся: Unrar API складніше, ніж хотілося б. Тому деякі перевірки на помилки і опису різних режимів "розархівації" я опустив навмисно.

Для більшої прозорості відбувається давайте кинемо на форму компоненти Memo і Button. Все, що відбувається в процесі розпакування вашого архіву буде фіксуватися в Memo. При натисканні кнопки відбуватиметься розархівування:

procedure TForm1.Button1Click (Sender: TObject); begin Memo1.Lines.Clear; UnRarFile ( 'C: \ Фото.rar'); end;

Ну, що, готові творити свої "UnRar - разархіватори"? Тоді, в путь!

unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class (TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click (Sender: TObject); private public end; var Form1: TForm1; implementation procedure LOG (S: string); begin Form1.Memo1.Lines.Add (S); end; type TRAROpenArchiveData = record ArcName: PChar; OpenMode: cardinal; OpenResult: cardinal; CmtBuf: PChar; CmtBufSize: cardinal; CmtSize: cardinal; CmtState: cardinal; end; TRARHeaderData = record ArcName: array [0 .. 259] of char; FileName: array [0 .. 259] of char; Flags: cardinal; PackSize: cardinal; UnpSize: cardinal; HostOS: cardinal; FileCRC: cardinal; FileTime: cardinal; UnpVer: cardinal; Method: cardinal; FileAttr: cardinal; CmtBuf: PChar; CmtBufSize: cardinal; CmtSize: cardinal; CmtState: cardinal; end; TUnRarCallBack = function (msg: Cardinal; UserData, P1, P2: integer): integer; stdcall; function RAROpenArchive (var ArchiveData: TRAROpenArchiveData): THandle; stdcall; external 'unrar.dll' name 'RAROpenArchive'; function RARCloseArchive (hArcData: THandle): Integer; stdcall; external 'unrar.dll' name 'RARCloseArchive'; function RARReadHeader (hArcData: THandle; out HeaderData: TRARHeaderData): Integer; stdcall; external 'unrar.dll' name 'RARReadHeader'; function RARProcessFile (hArcData: THandle; Operation: Integer; DestPath: pchar; DestName: pchar = nil): Integer; stdcall; external 'unrar.dll' name 'RARProcessFile'; procedure RARSetCallback (hArcData: THandle; Callback: TUnRarCallback; UserData: longint); stdcall; external 'unrar.dll' name 'RARSetCallback'; const ERAR_END_ARCHIVE = 10; RAR_OM_EXTRACT = 1; RAR_EXTRACT = 2; RAR_SUCCESS = 0; UCM_PROCESSDATA = 1; var RARHeaderData: TRARHeaderData; ArcStruct: TRAROpenArchiveData; CmtBuffer: array [0 .. 1023] of char; function UnRarCallBack (msg: Cardinal; UserData, P1, P2: integer): integer; stdcall; begin Result: = 0; if msg = UCM_PROCESSDATA then LOG ( 'розпакувати' + IntToStr (P2) + 'байт'); end; function OpenRARArchive (FileName: string): THandle; begin ZeroMemory (@ArcStruct, sizeof (ArcStruct)); ArcStruct.OpenMode: = RAR_OM_EXTRACT; ArcStruct.ArcName: = pchar (FileName); ArcStruct.CmtBuf: = CmtBuffer; ArcStruct.CmtBufSize: = sizeof (CmtBuffer); Result: = RAROpenArchive (ArcStruct); end; procedure UnRarFile (RarFileName: string; Directory: string = ''); var hRAR: THandle; hReadHeader: integer; hProcessHeader: integer; begin UniqueString (RarFileName); RarFileName: = ExpandFileName (RarFileName); UniqueString (Directory); if length (Directory) = 0 then Directory: = ChangeFileExt (RarFileName, '') else Directory: = ExpandFileName (Directory); LOG ( 'розпаковувати архів "' + RarFileName + '" в папку "' + Directory + '" ...'); CharToOem (pchar (Directory), pchar (Directory)); hRAR: = OpenRARArchive (RarFileName); RARSetCallback (hRar, UnRarCallBack, 0); hReadHeader: = 0; hProcessHeader: = 0; REPEAT hReadHeader: = RARReadHeader (hRar, RARHeaderData); if hReadHeader = ERAR_END_ARCHIVE then Break;

Перш, ніж почати розбиратися з кодом, давайте краще попрактікуемся! Перенесіть вищевказаний програмний код в свій проект, розтягніть Memo ширше, Memo.ScrollBars задайте ssBoth, в обробнику TForm1.Button1Click вкажіть реально існуючий rar-архів. Запускайте додаток, тисніть на кнопку. У мене вийшло що щось на зразок:

Розпаковую архів "C: \ фото.rar" в папку "C: \ фото" ... розпаковую файл "МОІ_ФОТКІ" ... 0 байт. Розпаковую файл "МОІ_ФОТКІ \ Ми З Любою" ... 0 байт. Розпаковую файл "МОІ_ФОТКІ \ Фотки Серьоги" ... 0 байт. Розпаковую файл "МОІ_ФОТКІ \ Ми З Любою \ DSCN1281.JPG" ... 307150 байт. Розпакував 307150 байт розпаковувати файл "МОІ_ФОТКІ \ Ми З Любою \ DSCN1282.JPG" ... 262913 байт. Розпакував 262913 байт розпаковувати файл "МОІ_ФОТКІ \ Ми З Любою \ Thumbs.db" ... 328192 байт. Розпакував 328192 байт розпаковувати файл "МОІ_ФОТКІ \ Фотки Серьоги \ PICT0391.JPG" ... 263412 байт. Розпакував 263412 байт розпаковувати файл "МОІ_ФОТКІ \ Фотки Серьоги \ PICT0392.JPG" ... 274698 байт. Розпакував 274698 байт розпаковувати файл "МОІ_ФОТКІ \ Фотки Серьоги \ Thumbs.db" ... 119296 байт. Розпакував 119296 байт розпаковувати файл "МОІ_ФОТКІ \ Фотки Серьоги \ Арія - Візьми моє сердце.mp3" ... 5066024 байт. Розпакував 4194045 байт розпакував 259 байт розпакував 871720 байт Все Розпаковано, закриваю архів.

Пропоную проаналізувати отриманий текст. Перший рядок показує, який архів разархивируем і в яку папку. Так як папку явно ми не вказували, папка "вибирається автоматично".

Наступні 3 рядки показують, що при розархівації, якщо в архіві є піддиректорії, спочатку створюється дерево каталогів. Розархівування самих файлів починається тільки з п'ятого рядка. Відразу зверніть увагу на останній разархівіруемий файл (який невідомо як опинився в моєму архіві фотографій) - mp3-трек групи "Кипелов". Вихідний mp3 файл займає близько 5мб (5066024 байт), проте розархівуйте він в 3 етапи. Перевіряйте: 5066024 = 4194045 + 259 + 871 720.

Питання: "Чому деякі файли розархівуйте всього в один етап?"

Відповідь: Все залежить від розміру і фактора стисливості архівіруемого файлу. Файл розбивається на частини, якщо він великий чи його розбиття призведе до кращої компресії.

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

відкрити файл-архів, отримати дескриптор цикл: прочитати заголовок (визначаємо, який файл разархивируем) розпакувати файл якщо не досягли кінця архіву, то знову прочитати заголовок закрити файл-архів

Тепер можна дивитися реалізацію процедури UnRarFile. Сподіваюся, багато стало зрозуміло.

Перед тим, як розпакувати якийсь файл, ми отримуємо його заголовок. Тема містить безліч параметрів: ім'я разархівіруемого файлу (FileName), розмір в архіві (PackSize), реальний розмір (UnpSize), атрибути файлу (FileAttr; по ним, до речі, можна дізнатися, директорія це чи ні), ряд інших параметрів. Якщо ви бажаєте розпакувати не весь архів, а тільки його частину (тільки * .exe-файли, наприклад) і на черзі непотрібний файл, то просто не викликайте функцію RARProcessFile.

До речі кажучи, якщо потрібно, підтримується розархівування "в інший файл". Для цього в останньому аргумент функції RARProcessFile вказувати не nil, а нове ім'я файлу. Не забувайте, що в UnRar рядки в OEM кодуванні.

Якщо результат цієї функції дорівнює нулю, розархівування триває. Якщо -1, то припиняється (інші значення не пробував). Цією особливістю користуються, щоб припустимо скасувати разархивацию.

Повідомлення (msg) може приймати не тільки константу UCM_PROCESSDATA, але і UCM_NEEDPASSWORD (коли архів запаролено) і UCM_CHANGEVOLUME (не знаю, як використовується);

Проте, найголовнішим залишається UCM_PROCESSDATA. Коли ви викликаєте процедуру RARProcessFile, файл може розпакувати по частинах. При кожній розархівації такої частини, викликається Callback функція з повідомленням UCM_PROCESSDATA; P2 - розмір разархівіруемой частини.

Разархивируя файл в тому ж WinRAR, ми бачимо 2 смуги стану: верхня (яка частина архіву вже розпакована, яка ще залишилася) і нижня (все те ж саме щодо поточного файлу). Як реалізувати нижню, думаю, припускаєте: при читанні заголовка потрібно дізнатися, скільки займає розпакований файл (зберегти в змінну Total, наприклад) і занулити якусь целочисленную змінну (Cur, наприклад). У Callback функції, при отриманні повідомлення UCM_PROCESSDATA, до Cur додаєте локальний параметр P2.

Відсоток = round (Cur / Total * 100).

Розрахувати відсоток розпакування всього архіву виявляється складніше. Навіть з урахуванням того, що розмір кожного файлу знаходиться елементарно (UnpSize), в структурі TRAROpenArchiveData немає ні натяку на що-небудь типу GlobalUnPackSize. Ну і як бути?

У будь-якому випадку, GlobalUnPackSize знайти все ж треба. Робиться це приблизно так (сильно спрощено):

GlobalUnPackSize: = 0; hRAR: = OpenRARArchive (RarFileName); RARSetCallback (hRar, UnRarCallBack, 0); While RARReadHeader (hRar, RARHeaderData) ERAR_END_ARCHIVE do Inc (GlobalUnPackSize, RARHeaderData.UnpSize); RARCloseArchive (hRAR); //

Так, згоден, ні про яку реалізації класу або вже тим більше компонента TUnRar, мови не йшло. Проте, сподіваюся, що все-таки знайдеться людина, яка візьметься за реалізацію нормального компонента, що не потребує dll, що працює коректно і щоб інтерфейс доброзичливий був.

Єдине, що заважає перенесенню поточної реалізації в ООП, це - функція UnRarCallBack. Заковика в тому, що якщо оголосити таку процедуру в public секції класу, то компілятор не дозволить поставити її в якості параметра функції RARSetCallback (). І справа тут не в компіляторі; справа в угодах про виклик на рівні асемблера.

На щастя, обходиться це річ просто. Останній аргумент функції RARSetCallback () - UserData: longint, займає чотири байти, в нього можна помістити посилання на компонент ...

Пояснюю. Припустимо, у нас є клас TUnRar. Створимо в ньому функцію TUnRar.RARCallBack (msg, P1, P2: integer): integer, яка в кінцевому рахунку і буде приймати всі повідомлення. Припустимо, буде так само процедура TUnRar.UnRarFile (), в якій виклик RARSetCallback () трохи змінимо:

RARSetCallback (hRar, UnRarCallBack, longint (self)); т

Ну а UnRarCallBack буде виглядати так:

function UnRarCallBack (msg: Cardinal; UserData, P1, P2: integer): integer; stdcall; begin Result: = TUnRar (UserData) .RARCallBack (msg, P1, P2); end;

Правда, здорово?

Як це не дивно, пару реалізацій таких компонентів я бачив. По-перше, це закритий компонент в пакеті ZipTV. Другий - німецький компонент (відкритий!) DFUnRar (качайте тут ). Обидва не зовсім зручні, росіянин не підтримують, вимагають unrar.dll.

Якщо скласти вихідні DFUnRar, одного ледачого ентузіаста і цю статтю, то можна зробити непоганий компонент. Ну а в мене, на жаль, часу немає.

Гаразд! Тепер позбавляємося від цієї unrar.dll !!!

Для мене, чесно кажучи, до сих пір не зрозуміло, чому ж багато програмісти прагнуть позбутися від наявності використовуваних dll в своїй директорії. Я скажу більше, я - один з таких програмістів :).

Кому-то, напевно, хочеться отримати деяку автономність свого застосування (якщо програма не знайде необхідну dll, то коректно воно працювати, м'яко кажучи, не буде). Хтось, напевно, хоче приховати використання платних (або безкоштовних) Dll-бібліотек (це і всілякі графічні, і скріптові, і звукові [BASS, MikMod, FMOD, ...], і фізичні [Newton, ODE, Tokamak, ...] движки , і комерційні dll-бібліотеки, і ...). Хтось, напевно, має безліч коду на Сі ++ і хоче використовувати його в Delphi; у кожного свої причини. Взагалі-то, використовувати Сі-шний код можна і не створюючи dll. Але це тема вже окремої статті ... (ладно, користуючись нагодою, напишу пізніше пару слів).

Мені відомі всього три способи інтеграції DLL в свій додаток:

  1. Включити DLL в файл ресурсів, файл ресурсів прілінкованние до свого додатком. При завантаженні, зберегти DLL в окремий (краще в папці "Temp") файл; динамічно завантажити всі функції з отриманої DLL.
  2. Скористатися утилітою Dll2Lib, програмувати на VisualC ++.
  3. Скористатися утилітами DLLTools.

Перший спосіб, сподіваюся, зрозуміла всім. Другий спосіб я поясню. Існує досить відома утиліта DLL2Lib. Вона, як можна здогадатися, конвертує DLL-бібліотеки в статичні * .lib-бібліотеки. Отриману * .lib можна вільно використовувати в додатках на Visual C ++. Builder C ++ теж використовує * .lib-бібліотеки, але спроба лінковки такої бібліотеки через несумісність форматів (про них поговоримо в кінці) закінчиться помилкою компілятора.

Поговоримо тепер про останньому способі. Зовсім недавно Vga дав мені посилання , За що йому величезне спасибі. Завантажувати там ні чого не треба, до статті вже додається істотно змінений архів DLLTools.zip. Саме його вам потрібно завантажити для подальшої роботи.

Архів містить всього 7 файлів (у справі тільки 3). Перше, що потрібно зробити, це скопіювати в якусь глобальну директорію (в $ Delphi \ Lib \, наприклад) модуль "DLLLoader.pas". Це основний модуль, його автором є Benjamin Rosseaux ( www.0ok.de ). Незважаючи на те, що цей і всі інші модулі проекту я, як уже казав, істотно змінив, справжнім автором залишається Benjamin Rosseaux.

Другий за важливістю є утиліта Dll2Pas (вона взагалі повністю переписана). Саме вона перетворює DLL в автономний * .pas файл-заготовку. Для того щоб їй скористатися, скопіюйте всі конвертовані DDL-бібліотеки в директорію DLLTools і запустіть утиліту. Якщо в директорії знаходиться тільки одна "UnRar.dll", то утиліта створить тільки один файл "UnRarLib.pas". Відкривши цей модуль в Delphi, ви побачите, що він "поділений" на кілька блоків:

  1. БЛОК КОНСТАНТ і ТИПІВ
  2. БЛОК ФУНКЦІЙ і ПРОЦЕДУР
  3. БЛОК ВНУТРІШНІХ ФУНКЦІЙ і ПРОЦЕДУР
  4. Ініціалізації ВСІХ ФУНКЦІЙ і ПРОЦЕДУР
  5. БЛОК деініціалізацію (якщо потрібно)

Давайте заповнимо деякі з них. У перший блок перемістіть опису всіх типів (TRAROpenArchiveData, TRARHeaderData, TUnRarCallBack) і констант (ERAR_END_ARCHIVE, RAR_OM_EXTRACT, RAR_EXTRACT, RAR_SUCCESS, UCM_PROCESSDATA), що відносяться до бібліотеки UnRar.

Другий блок поки пропустимо, в третій перенесемо допоміжну функцію OpenRARArchive (). Всі змінні (RARHeaderData, ArcStruct, CmtBuffer) перемістіть в секцію interface (тобто вище секції implimentation).

П'ятий блок нам взагалі не потрібен (видаляти його не обов'язково). Залишилося заповнити другий і четвертий. Якщо свою DLL ви завантажуєте динамічно, то вам не складе великих зусиль заповнити ці блоки. Якщо ви завантажуєте її статично (як в нашому випадку), то на допомогу приходить утиліта Static2DynDLL. Користуватися їй так:

  1. У файл "PROCS.txt" скопіювали свої статичні функції. Коментарі, якщо є, видаляти не обов'язково. Опис всій функції повинно бути у всю рядок:
  2. function RARCloseArchive (hArcData: THandle): Integer; stdcall; external 'unrar.dll' name 'RARCloseArchive'; . . .
  3. Запускаєте утиліту Static2DynDLL
  4. Вміст файлу "pointers.txt" копіюєте до другого блоку:
  5. RAROpenArchive: function (var ArchiveData: TRAROpenArchiveData): THandle; stdcall; RARCloseArchive: function (hArcData: THandle): Integer; stdcall; RARReadHeader: function (hArcData: THandle; out HeaderData: TRARHeaderData): Integer; stdcall; RARProcessFile: function (hArcData: THandle; Operation: Integer; DestPath: pchar; DestName: pchar = nil): Integer; stdcall; RARSetCallback: procedure (hArcData: THandle; Callback: TUnRarCallback; UserData: longint); stdcall;
  6. Вміст файлу "load" копіюєте в четвертий блок:
  7. RAROpenArchive: = GetProcedure ( 'RAROpenArchive'); RARCloseArchive: = GetProcedure ( 'RARCloseArchive'); RARReadHeader: = GetProcedure ( 'RARReadHeader'); RARProcessFile: = GetProcedure ( 'RARProcessFile'); RARSetCallback: = GetProcedure ( 'RARSetCallback');

От і все! Тепер ви - власники статичної бібліотеки "UnRar" для Delphi !!! Запускайте своє тестове додаток і насолоджуйтеся життям. На всякий випадок, якщо когось зацікавить, яким чином насправді відбувається завантаження DLL, читайте исходники DLLLoader.pas і статтю Завантажувач PE-файлів .

Питання: Чому отриманий модуль додає до exe в 2 рази менше, ніж вихідна DLL? Чи не тому, що видаляє з DLL непотрібні шматки коду?

Відповідь: Ні. Насправді використовується inflate-стиснення. Такий підхід економить не тільки розмір exe, але і займане місце в пам'яті.

Питання: Чому отриманий модуль в 2 рази більше, ніж вихідна DLL?

Відповідь: Для того щоб "вписати" дані всередину * .pas-файлу, використовується масив байт. На опис 1байт даних йде 4байта (символу) тексту. Оскільки вихідний файл стиснутий приблизно в 2 рази, а на запис кожного байта йде 4байта, то: результат = розмір (DLL) / 2 * 4 = 2 * розмір (DLL) ... Дані навряд чи будуть записуватися інакше!

Питання: В процесі роботи мого програми відбувається помилка доступу до пам'яті за адресою 0. Як лікувати?

Відповідь: Або якийсь із функцій немає в DLL, або статична функція була неправильно конвертована утилітою Static2DynDLL. Наприклад, якщо статична функція виглядає так:

function MessageBox (...): Integer; stdcall; external user32 name 'MessageBoxA';

то утиліта перетворює в: MessageBox: = GetProcedure ( 'MessageBox'); Всі питання до Benjamin Rosseaux!

Питання: У моїй DLL "зашиті" ресурси. Як їх звідти можна завантажити?

Відповідь: Поняття не маю. Можете вивчити вихідні коди і зазначену вище статтю, щоб додати таку можливість в TDLLLoader (якщо таке можливо).

Питання: які зміни вніс ти?

відповідь:

  1. стиснення
  2. розділив отриманий файл на блоки-коментарі
  3. змінив конструктор і опис класу TDLLLoader
  4. функція GetProcedure ( '') перестала бути чутлива до регістру аргументу
  5. Dll2Pas заробила на порядок швидше і відразу з усіма Dll в директорії
  6. змінені імена файлів на вході і виході утиліти Static2DynDLL

Усе! Успіхів вам! Я тут поки кілька днів статтю і утиліти писав, зі своєю дівчиною посварився; каже, весь час за комп'ютером проводжу, їй уваги майже не приділяю. Все, бувай!

Так, мало не забув, що обіцяв розповісти про це. Гаразд. Найпростіший і надійний спосіб - перетворити С ++ код в DLL, яку без проблем можна використовувати в своєму додатку.

По-друге можна постаратися відкомпілювати код в одному з C ++ компіляторів формату OMF, а отримані * .obj файли прілінкованние до свого додатком директивою {$ L ...}. "Що за формат такий - OMF" - запитають деякі. Справа в тому, що існують два несумісних формату * .obj-файлів: OMF і COFF. Перший використовується в Delphi, C ++ Builder, Watcom C ++, Intel C ++ Compiler, ..., другий використовується в Visual C ++ і деяких інших компіляторах.

Можна, правда, скористатися утилітою Coff2Omf . Для того щоб їй скористатися, створіть файл, наприклад, "Execute.bat" такого змісту:

COFF2OMF.EXE MyObjFile.obj pause

Потім запустіть цей файл на виконання, повинен вийти файл формату OMF.

Але, якщо все ж є можливість скомпілювати його в OMF-компіляторі, то відкомпілюйте в ньому. вісь список безкоштовних Сі ++ компіляторів . можна завантажити безкоштовний Борландовскій C ++ компілятор .

Завантажено? Тепер заради інтересу спробуйте взяти якийсь C ++ модуль, відкомпілювати його і, якщо потрібно, перетворити його в OMF. Тепер спробуйте прілінкованние його до Delphi ... Помилка? Я так и думав! Ось майже дослівно те, що з даного приводу пише Kvant на форумі сайту RSDN :

Delphi розуміє OMF об'єктні файли, та й то з деякими обмеженнями. Обмежень, в основному, 3 штуки:

  1. Виклики функцій через імпорт в Delphi зводяться до формату "call [jmp адреса]". Якщо в об'ектніке вказано просто "call адреса", компілятор Delphi видасть помилку.
  2. Імена імпортованих функцій не повинні містити декорації (типу _imp__імя @ N), за винятком борландовского формату.
  3. Фіксапи (записи FIXUPP) повинні бути виключно 5-байтними.

Є ще обмеження на імена секцій, TLS і т.д. Проте, в більшості випадків досить мати на увазі лише ті 3 вищеописаних обмеження, щоб отримати працездатний OMF-об'ектнік без використання сторонніх утиліт.

Рекомендую глянути на документацію та вихідні утиліти OMF2D by EliCZ .

Ось тепер точно Все!

PS мене по даній темі питати нічого не треба, тому що я не прілінкованние до Delphi-додатком ще жодного об'ектніка, написаного на Сі; вся інформація отримана з Інтернету і зі слів Vga.


До матеріалу додаються файли:
[ Використання і створення DLL ] [ Архівація (алгоритми стиснення) ]
Обговорення матеріалу [02-07-2008 5:22] 39 повідомленьНу і як бути?
Чи не тому, що видаляє з DLL непотрібні шматки коду?
0. Як лікувати?
Як їх звідти можна завантажити?
Завантажено?
Помилка?


Новости
  • Виртуальный хостинг

    Виртуальный хостинг. Возможности сервера распределяются в равной мере между всеми... 
    Читать полностью

  • Редизайн сайта

    Редизайн сайта – это полное либо частичное обновление дизайна существующего сайта.... 
    Читать полностью

  • Консалтинг, услуги контент-менеджера

    Сопровождение любых интернет ресурсов;- Знание HTML и CSS- Поиск и обновление контента;-... 
    Читать полностью

  • Трафик из соцсетей

    Сравнительно дешевый способ по сравнению с поисковым и контекстным видами раскрутки... 
    Читать полностью

  • Поисковая оптимизация

    Поисковая оптимизация (англ. search engine optimization, SEO) — поднятие позиций сайта в результатах... 
    Читать полностью