#import TLB

Вопросы по языкам программирования Си и С++.
Федор Конюхов
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 21.03.2012 (Ср) 7:49

#import TLB

Сообщение Федор Конюхов » 21.03.2012 (Ср) 8:33

Добрый день.
Возник вопрос по директиве #import

Есть некая длл без исходников и есть tlb, сгенерированная с помощью MIDL из
файла idl примерно такого содержания:
Код: Выделить всё

[uuid(90000000-4000-4000-8000-0c0000000000)]
library twix
{
    [dllname("twix.dll")]
    module twix
    {
        [entry("TWInit")]
        long __stdcall  TWInit();
        //... 
    };
};


Я использовал это в бейсике, подключая ссылку на tlb в references и вызывал функцию TWInit не задумываясь.
И вот захотел создать такую же связь с длл в проекте c++.
Код: Выделить всё
#import "twix.tlb"
int main (int argc, _TCHAR* argv[])
{
    long b = twix::TWInit();

    return 0;
}

В результате:
error LNK2019: unresolved external symbol "long __stdcall twix::TWInit(..... referenced in function _DllMain
Ну понятно, прототип функции есть, реализации нет.
Собственно вопрос, на кой тогда нужна директива #import TLB, если придеться все равно связывать динамически:
Код: Выделить всё
typedef  long(__stdcall *PTR) ();
    PTR  pFnc  = (PTR) GetProcAddress(GetModuleHandleA("twix"), "TWInit"));
    (pFnc)();


Или я чего-то не учел и все проще?

.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 21.03.2012 (Ср) 10:29

Федор Конюхов писал(а):Собственно вопрос, на кой тогда нужна директива #import TLB, если придеться все равно связывать динамически:

Директива нужна для того, чтобы импортировать из TLB прототипы функций.
Прототипы функций нужны компилятору — используя прототипы, компилятор проверяет правильность вызова (соответствие количества и типов передаваемых параметров, соответствие типа возврата), а так же использует информацию о соглашении (stdcall / cdecl / / fastcall / thiscall), чтобы сгенерировать правильный машинный код для вызова.

Но компилятор не имеет на руках реализации функции, поэтому генерирует обращение к внешней сущности. В произведённом компилятором obj-файле просто хранится информация обо всех обращениях к внешним сущностям. Даже если этих внешних сущностей вообще не существует в природе.

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

Дело в том, что логика работы компилятора не привязана к конкретной системе. Ни в С/С++ нет средств пометить функцию, как импортируемую из DLL-библиотеки, ни компилятор C/C++ не умеет и не должен уметь генерировать PE-формат-специфичную таблицу импорта.

Чтобы решить эту проблему, существуют так называемые «библиотеки импорта». Это крохотные статические библиотечки (lib-файлы), которые содержат внутри себя переходники, необходимые для импорта функций из DLL. Стоит только подсунуть соответствующую import-lib-ку линкеру, и external symbol перестанет быть unresolved. Он станет resolved, а в таблицу импорта попадёт соответствующий элемент, необходимый для импорта функции TWinit из твоей DLL-шки.

В общем, если коротко: для того, чтобы поюзать из C++-программы какую-нибудь DLL-ку, необходимо для вещи:
  1. h-файлы, содержащие прототипы нужных функций — нужны компилятору
  2. lib-файлы, содержащие import thunk-и — нужны линкеру

Идея директивы #importlib в том, чтобы заменить h-файлы одной tlb-шкой. h-файлы нужны компилятору в любом случае, но директива #importlib позволяет сгенерировать h-файлы автоматически на основе TLB-шки. С этой задачей директива справляется на ура.

Но она не отменяет необходимости в lib-файлах. lib-файлы нужны абсолютно всегда: не важно, системная ли это библиотека, или какая-то своя произвольная. Когда мы компилируем DLL-шку, причём не важно, компилируем из под VB6 или же из под C++ — всегда автоматически генерируется lib-файл и exp-файл для этой DLL-шки. Они нужны как раз на этот случай.

В общем, тебе нужно найти этот lib-файл для своей библиотеки. Без него никак.

Другое дело в том, что информация в нём настолько тривиальна, что даже если оригинальный lib-файл найти не получится, его можно будет сгенерировать с нуля — исходники оригинальной библиотеки для этого совсем не требуются.

Прочитай ещё вот это, чтобы устранить недопонимание сути момента.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Федор Конюхов
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 21.03.2012 (Ср) 7:49

Re: #import TLB

Сообщение Федор Конюхов » 21.03.2012 (Ср) 11:42

Хакер, спасибо за такой быстрый и подробный ответ.
Многое в голове встало на свои места.
Зацеплюсь за Вашу фразу:
lib-файлы, содержащие import thunk-и — нужны линкеру
...
даже если оригинальный lib-файл найти не получится, его можно будет сгенерировать с нуля

Может надо бы как следует погуглить, чем сразу спрашивать, но все же... :)
Каким инструментом это осуществить? То есть надо как-то прочитать адреса экспортируемых функций, (видимо в dll должна быть секция/таблица?)
и записать их в lib-файл вместе с именами/параметрами, учитывая спецификацию формата lib?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 21.03.2012 (Ср) 12:37

Вообще, по идее, раз они сделали #importlib, который автоматически генерирует h-файлы на основе TLB, они должны были сделать ответную часть для линкера — чтобы генерировались lib-ки на основе TLB. Потому что в TLB есть информация и для того, и для другого. Но я не помню таких утилит, и не помно, чтобы у линкера были ключи командной строки для чего-то подобного. Может быть в новых студиях что-нибудь добавили?

В общем, самый простой (тупой) способ:
Создать исходник, в котором «реализуешь» (пустышками) функции интересующей DLL-библиотеки:

dummy.c:
Код: Выделить всё
long __stdcall TWinit() { return 777;}
long __stdcall TWAnotherOneFunction { return 777; }


dummy.def:
Код: Выделить всё
LIBRARY имя_реальной_dll
EXPORTS
    TWInit
    TWAnotherOneFunction


Из командной строки:
cl /Fe:dummy.dll dummy.c /link /def:dummy.def

В результате возникнет dummy.dll и dummy.lib.
dummy.dll можно смело удалять, а dummy.lib использовать как недостающую импортлибку.

Более умный способ: правильным образом написать def-файл и без всяких C-файлов сделать так:
lib /def:dummy.def /out:нужный_файл.lib
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Федор Конюхов
Начинающий
Начинающий
 
Сообщения: 3
Зарегистрирован: 21.03.2012 (Ср) 7:49

Re: #import TLB

Сообщение Федор Конюхов » 21.03.2012 (Ср) 13:11

Господи, до чего же Вы понятно объясняете!
Порядок и количество функций должно ли как-то соответствовать тому как отображается в Dependency Walker? Допустимы ли пропуски, если нужно, скажем, первая и третяя функция.
Впрочем, что я спрашиваю. Взять, да проверить.

Хакер, спасибо за Вашу компетентость!

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 21.03.2012 (Ср) 15:40

Федор Конюхов писал(а):Порядок и количество функций должно ли как-то соответствовать тому как отображается в Dependency Walker?

Порядок не важен.
Количество — только то, которое необходимо. Но есть смысл делать lib-ку, охватывающую все функции.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: #import TLB

Сообщение ger_kar » 26.03.2012 (Пн) 11:04

Хакер писал(а):h-файлы нужны компилятору в любом случае, но директива #importlib позволяет сгенерировать h-файлы автоматически на основе TLB-шки. ...
Но она не отменяет необходимости в lib-файлах. lib-файлы нужны абсолютно всегда: не важно, системная ли это библиотека, или какая-то своя произвольная. ...
Вообще, по идее, раз они сделали #importlib, который автоматически генерирует h-файлы на основе TLB, они должны были сделать ответную часть для линкера — чтобы генерировались lib-ки на основе TLB. Потому что в TLB есть информация и для того, и для другого.
Блин на дворе 21 век, можно же было бы и компилятор с линковщиком сделать на современный лад, VB же обходится информацией спрятанной в TLB, почему бы и в Си не пойти тем же путём, а то получилось городьба огорода на ровном месте. Это все равно, что удаление гландов, через задний проход.
+ VB и огромный - C/C++
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 26.03.2012 (Пн) 13:56

ger_kar
Не надо писать ерунду.

Задача компилятора Си — из исходника произвести на свет obj-файл. Всё остальное, чем бы оно не было, уже не задача компилятора Си, и поэтому даже никакого отношения к компилятору Си не имеет.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: #import TLB

Сообщение ger_kar » 26.03.2012 (Пн) 17:28

Хакер писал(а):Задача компилятора Си — из исходника произвести на свет obj-файл. Всё остальное, чем бы оно не было, уже не задача компилятора Си, и поэтому даже никакого отношения к компилятору Си не имеет.
Во первых я писал не про компилятор, а про сладкую парочку компилятор+линковщик, во вторых, то что относится к компетенции компилятора, а именно произведение на свет obj-файла, используя информацию из TLB делается через одно известное место на ж..., потому как, сначала генерируется хидер, а потом уже информация из него используется при компиляции (об этом кстати ты писал). Конечно так видимо было проще, подправили на скорую руку, вместо того, что-бы сделать это основательно. Ведь VB используя TLB никакие хидеры сначала не лепит. Ну и в третьих до кучи к компилятору и линковщик сделан так же убого, хотя можно было-бы и его научить полноценному использованию TLB. Одно дело, когда Antonary для себя делает инструмент для генерации TLB используя подобный принцип и другое дело, когда это делает такая большая корпорация. Почему-бы было не сделать нормальную полноценную поддержку TLB, которая фактически могла бы заменить и хидеры и либы. Мне кажется если бы ты это делал вместо MS, ты бы этим путем и пошел и сделал бы это как следует, а не абы как, как это сделали в MS.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 26.03.2012 (Пн) 17:59

ger_kar писал(а):Во первых я писал не про компилятор, а про сладкую парочку компилятор+линковщик

Тогда какого фига ты поставил минус языкам Си/Си++? Линковщик не имеет никакого отношения ни к компилятору, ни к какому-либо из любых существующих в мире языков (включая Си и Си++).

ger_kar писал(а):используя информацию из TLB делается через одно известное место на ж...

Нет. Это делается единственным правильным путём. Есть языки, которые стандартизирются, и для которых выпускают стандарты. Стандарт — это святое. Может быть пятьдесят миллиардов компиляторов от разных фирм, но если все они соответствуют стандарту, то одинаковый код скомпилировавшись на всех них даст одинаковый результат.

А если бы была куча компиляторов, и каждому нужен бы был немножечко-свой видоизменённый язык Си, это вообще никому не было бы нужно.

Так вот, язык Си один. Един. И его природа такова, что любая сущность, к которой есть обращение в коде, должна быть явно задекларирована. Задекларирована не святым духом, а строчкой на языке Си/Си++. Поэтому если #importlib не генерировал промежуточных файлов, то получилось бы, что есть строчки, обращающиеся к сущности, но нигде нет строчек, в которых сущность объявляется. Это недопустимо. И даже недопустимость этого недопустимо подвергать малейшему сомнению. Точка.

ger_kar писал(а):Ведь VB используя TLB никакие хидеры сначала не лепит.

Причём тут VB? VB это вещь совершенно иного порядка. Критически иного. Настолько, что упоминать его в рамках этой беседы вообще нельзя.

ger_kar писал(а):Одно дело, когда Antonary для себя делает инструмент для генерации TLB подобный принцип и друге, когда это делает такая большая корпорация. Почему-бы было не сделать нормальную полноценную поддержку TLB, которая фактически могла бы заменить и хидеры и либы.

Потому что это идеологически неправильно. Если ты не понимаешь идеологии, а вернее сказать, ты попросту не чувствуешь идеологии, то это не значит, что на пустом месте, которое в реальности вовсе не пустое, нужно строить свои воздушные замки.

ger_kar писал(а):Мне кажется если бы ты это делал вместо MS, ты бы этим путем и пошел и сделал бы это как следует, а не абы как, как это сделали в MS.

Аргхг!! Как будто бы MS имеет какие-то привилегии решать, как устроен язык Си (и С++), как устроена модель компиляции и тому подобное.

Есть схема. Устоявшаяся. Есть 237 языков, от L1 до L237. Есть 12475 компиляторов для этих языков. На какие-то языки приходится несколько разных компиляторов. Есть 900 исходных файлов на разных языках (их множества 237 языков). Некоторые файлы их этих 900 написаны на одинаковом языке. Есть 49 линкеров, линкующих исполняемые файлы под 27 совершенно разных операционных систем.

И суть схемы в том, что для любого из 900 исходных файлов можно применить любой из 12475 компиляторов (лишь тех из них, что соответствуют языку конкретно взятого исходного файла). В результате получится 900 объектных файлов. Совершенно одинаковых и никак в теории не зависящих от того, какой из 237 языков (и 12475 компиляторов) использовался для создания каждого из них. А потом можно взять любой из 49 линкеров и слинковать эти 900 объектных файлов в один исполняемый файл под любую из 27 совершенно разных операционных систем.

В этой абсолютно универсальной схеме, не заморачивающейся ни на конкретных языках программирования, ни на конкретных компиляторах, ни на конкретных линковщиках, ни на конкретных аппаратных платформах, ни на конкретных программных платформах... в ней места такой невероятно узкоспециальной вещи как TLB.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: #import TLB

Сообщение ger_kar » 26.03.2012 (Пн) 18:37

Хорошая лекция!
Хакер писал(а):Аргхг!! Как будто бы MS имеет какие-то привилегии решать, как устроен язык Си (и С++), как устроена модель компиляции и тому подобное.
Ну родили же они свой C# и здесь могли родить, пусть это был бы уже на C++, а МSС++ (что бы не нарушать стандарт), хотя и стандарт это не вселенская недвижимость, а всего лишь соглашение следовать определенным правилам, но жизнь на месте не стоит, поэтому и стандарты могли бы и пересмотреть
Хакер писал(а):А если бы была куча компиляторов, и каждому нужен бы был немножечко-свой видоизменённый язык Си, это вообще никому не было бы нужно.
Ну опять же, захотели MS родить C# и родили и появился еще один компилятор и втюхали они его огромной массе народа, и стал этот компилятор сразу очень нужным очень многим. Конечно C# и C++ языки разные, но и что с того, появился бы еще один, который бы включил в себя все новые достижения и удобные фишки, при этом оставаясь по сути C++ и многие не ломая своего сознания просто бы воспользовались новым и удобным инструментом. Глядишь со временем и С++, со своими рудиментальными хидерами потихоньку бы ушел с арены, как отживший свой век и уступил бы место новым видам :) в глобальном масштабе устоявшейся схемы, тем самым меняя и саму эту схему.
Бороться и искать, найти и перепрятать

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 26.03.2012 (Пн) 18:40

ger_kar писал(а):Ну родили же они свой C#

И что? В C# от C/C++ — только буква в названии да фигурные скобки.

ger_kar писал(а):С++, со своими рудиментальными хидерами

Величайшая глупость, считать, что это рудименты.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ger_kar
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1957
Зарегистрирован: 19.05.2011 (Чт) 19:23
Откуда: Кыргызстан, Иссык-Куль, г. Каракол

Re: #import TLB

Сообщение ger_kar » 26.03.2012 (Пн) 19:43

Хакер писал(а):Величайшая глупость, считать, что это рудименты.
Может и глупо, просто по сравнению с такой технологией как TLB, хидеры смотрятся уж как то очень не по современному.
Бороться и искать, найти и перепрятать

VBTerminator
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 415
Зарегистрирован: 19.11.2008 (Ср) 20:10

Re: #import TLB

Сообщение VBTerminator » 30.03.2012 (Пт) 14:50

ger_kar писал(а):хидеры смотрятся уж как то очень не по современному.

Зато заголовочные файлы, в отличие от библиотек типов, позволяют объявлять псевдонимы типов данных (через typedef) и не навязывают тип вызова safecall.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: #import TLB

Сообщение Хакер » 30.03.2012 (Пт) 15:02

VBTerminator писал(а):Зато заголовочные файлы, в отличие от библиотек типов, позволяют объявлять псевдонимы типов данных

TLB-шки точно так же позволяют. typedef («alias» по терминологии TLB) — один из типов сущности, хранимой в TLB.

И TLB абсолютно не навязывает safecall.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.


Вернуться в С/С++

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5

    TopList