Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Visual Basic Новый топик    Ответить
 Линковка статических библиотек OBJ/LIB к VB-экзешнику  [new]
Eolt
Member

Откуда:
Сообщений: 1332
Интересует как использовать статическую линковку в VB.

1. Вариант. Написание кода статических библиотек самостоятельно на C++, компиляция и линковка с VB-exe.

2. Вариант. Конвертация уже существующих DLL в статическую библиотеку и линковка с VB-exe.

Желательно с примерами проектов и архивчиком *.lib для Link.exe )
25 янв 19, 16:01    [21794409]     Ответить | Цитировать Сообщить модератору
 Re: Линковка статических библиотек OBJ/LIB к VB-экзешнику  [new]
ATM-TURBO 2
Member

Откуда:
Сообщений: 165
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]     Ответить | Цитировать Сообщить модератору
 Re: Линковка статических библиотек OBJ/LIB к VB-экзешнику  [new]
Eolt
Member

Откуда:
Сообщений: 1332
Cпасибо большое! Буду пробовать.
25 янв 19, 16:58    [21794464]     Ответить | Цитировать Сообщить модератору
Все форумы / Visual Basic Ответить