Добро пожаловать в форум, Guest >> Войти | Регистрация | Поиск | Правила | | В избранное | Подписаться | ||
Все форумы / Visual Basic |
![]() ![]() |
Eolt Member Откуда: Сообщений: 1553 |
Интересует как использовать статическую линковку в VB. 1. Вариант. Написание кода статических библиотек самостоятельно на C++, компиляция и линковка с VB-exe. 2. Вариант. Конвертация уже существующих DLL в статическую библиотеку и линковка с VB-exe. Желательно с примерами проектов и архивчиком *.lib для Link.exe ) |
25 янв 19, 16:01 [21794409] Ответить | Цитировать Сообщить модератору |
ATM-TURBO 2 Member Откуда: Сообщений: 168 |
Eolt, Слинковать объектный файл с объектными файлами сделанными в VB6 не проблема. Существует как минимум 2 пути. Первый легкий, но он добавляет нежелательный экспорт к исполняемому файлу. Для этого просто нужно в опциях линкера (LinkSwitches) указать параметр EXPORT с нужными функциями и соответственно указать библиотеку для компоновки. Библиотеки написанные на C/C++ требуют инициализацию рантайма поэтому в качестве точки входа (параметр ENTRY) следует указать mainCRTStartup (_DllMainCRTStartup для DLL). Данная функция инициализирует рантайм и передает управление функции main (wmain). Т.к. точка входа в вб программу называется __vbaS то необходимо как то передать туда управление вместо main. Простейший способ - это написание тривиального редиректора на FASM: ; init_runtime.asm format MS COFF section '.text' code readable executable public _main extrn ___vbaS _main: jmp ___vbaS Здесь просто происходит прыжок на точку входа VB6 EXE файла. При соблюдении этих условий будет выполнена инициализация сначала рантайма C/C++ затем инициализация рантайма VB. К примеру, имеем статическую библиотеку со следующим кодом: #include <iostream> #include <Windows.h> using namespace std; void _stdcall WriteToConsole(BSTR pszString) { wcout << pszString; } void _stdcall ReadFromConsole(BSTR *pszRet) { WCHAR pszBuf[255]; wcin.getline(pszBuf, 255); *pszRet = SysAllocString(pszBuf); } Нам нужно прилинковать статически этот код к EXE файлу сделанному в VB6. Нужно создать 2 версии библиотеки DLL и OBJ/LIB, соответственно для отладки в IDE и для скомпилированного варианта. В VB код будет таким: Option Explicit #If INIDE Then Public Declare Sub WriteToConsole Lib "..\static_lib\testlib\release\testdll" ( _ ByVal pszValue As Long) Public Declare Sub ReadFromConsole Lib "..\static_lib\testlib\release\testdll" ( _ ByVal ppszValue As Long) Public Declare Function AllocConsole Lib "kernel32" () As Long Public Declare Function FreeConsole Lib "kernel32" () As Long Public Declare Function SetDllDirectoryW Lib "kernel32" ( _ ByVal pszString As Long) As Long #Else Public Declare Sub WriteToConsole Lib "SimpleWay.exe" Alias "?WriteToConsole@@YGXPAG@Z" ( _ ByVal pszValue As Long) Public Declare Sub ReadFromConsole Lib "SimpleWay.exe" Alias "?ReadFromConsole@@YGXPAPAG@Z" ( _ ByVal ppszValue As Long) #End If В этом случае будет происходить вызов функции из DLL при значении константы условной компиляции INIDE = True и вызов функции из себя же при False. Пример использования: Option Explicit Sub Main() #If INIDE Then AllocConsole SetDllDirectoryW StrPtr(App.Path) #End If Dim sName As String WriteToConsole StrPtr("Hello! What's your name?" & vbNewLine) ReadFromConsole VarPtr(sName) WriteToConsole StrPtr("How are you, " & sName & "?" & vbNewLine) sName = vbNullString ReadFromConsole VarPtr(sName) #If INIDE Then FreeConsole #End If End Sub Для того чтобы обеспечить линковку просто указываем параметры линкеру: [VBCompiler] LinkSwitches=OleAut32.lib ..\init_runtime.obj ..\static_lib\testlib\Release\testlib.lib -SUBSYSTEM:CONSOLE -EXPORT:?ReadFromConsole@@YGXPAPAG@Z -EXPORT:?WriteToConsole@@YGXPAG@Z -ENTRY:mainCRTStartup Данные опции задают консольную подсистему, задают точку входа и экспортируемые функции. Здесь есть одна проблема с родным линкером - в нем есть баг при использовании опции OPT:REF - он отбрасывает импорт от основного EXEшника, поэтому если используется родной линкер то необходимо указать OPT:NOREF также. При использовании нового линкера данные действия необязательны. После компиляции получаем нужный результат: ![]() ____________________________________________________________________________________________ Другой способ более сложен, но избавляет от нежелательного экспорта. Данный способ использует замену модуля во время линковки. Для этого необходимо писать специальный Add-in либо использовать мой TrickAdvancedTools (с открытыми исходниками, но нем есть баги которые я не могу/хочу в данный момент исправлять) в качестве вспомогательного средства. В этом случае вместо импорта функций из себя же, придется создать отдельный стандартный модуль с функциями-пустышками с необходимыми прототипами. В свойствах Add-in'а необходимо выбрать события компиляции (before linking) и прописать там BATCH файл который будет заменять модуль пустышку на модуль переходник. Модуль переходник такой же тривиальный, следует только учесть что символы будут вида ?FuncName@ModuleName@@AAGXXZ (декорированные) и выполняет функции прыжка на необходимые linked символы. К примеру все тоже самое как и в первом примере, только без экспорта. Модуль изменится на: Option Explicit #If INIDE Then Public Declare Sub WriteToConsole Lib "..\static_lib\testlib\release\testdll" ( _ ByVal pszValue As Long) Public Declare Sub ReadFromConsole Lib "..\static_lib\testlib\release\testdll" ( _ ByVal ppszValue As Long) Public Declare Function AllocConsole Lib "kernel32" () As Long Public Declare Function FreeConsole Lib "kernel32" () As Long Public Declare Function SetDllDirectoryW Lib "kernel32" ( _ ByVal pszString As Long) As Long #Else Public Sub WriteToConsole( _ ByVal pszValue As Long) End Sub Public Sub ReadFromConsole( _ ByVal pszValue As Long) End Sub #End If Здесь просто вызываются функции пустышки при INIDE = False (компиляции). Также создается простой редиректор: format MS COFF section '.text' code readable executable WriteToConsole equ ?WriteToConsole@@YGXPAG@Z ReadFromConsole equ ?ReadFromConsole@@YGXPAPAG@Z extrn WriteToConsole extrn ReadFromConsole public ?WriteToConsole@modStaticLib@@AAGXXZ public ?ReadFromConsole@modStaticLib@@AAGXXZ ?WriteToConsole@modStaticLib@@AAGXXZ: jmp WriteToConsole ?ReadFromConsole@modStaticLib@@AAGXXZ: jmp ReadFromConsole modStaticLib здесь - имя заменяемого модуля. Следующий шаг - замена оригинального modStaticLib.OBJ на редиректор перед линковкой: del modStaticLib.obj copy asm\modStaticLib.obj modStaticLib.obj И установить событие перед линковкой: ![]() Последний шаг - удалить экспорты которые были добавлены в предыдущем способе: [VBCompiler] LinkSwitches=OleAut32.lib ..\init_runtime.obj ..\static_lib\testlib\Release\testlib.lib -SUBSYSTEM:CONSOLE -ENTRY:mainCRTStartup Все, можно компилировать и получить монолитный файл: ![]() Все файлы прикладываю. К сообщению приложен файл (static link test.rar - 131Kb) cкачать ![]() |
25 янв 19, 16:52 [21794460] Ответить | Цитировать Сообщить модератору |
Eolt Member Откуда: Сообщений: 1553 |
Cпасибо большое! Буду пробовать. |
25 янв 19, 16:58 [21794464] Ответить | Цитировать Сообщить модератору |
Все форумы / Visual Basic | ![]() |