Доступ к объектам главного окна из Dll?
Или к ProgressBar, чтобы отразить ход процесса идущего в DLL...
Подскажите как это сделать.
Здравствуйте, подскажите пожалуйста, можно ли из функции находящейся в DLL получить доступ к, скажем, объекту Memo расположенном в главном окне и записать туда строку?
Или к ProgressBar, чтобы отразить ход процесса идущего в DLL...
Смотри обсуждение в соседней ветке
А так не получится?
extern "C" __declspec(dllexport) void AddLine(TStrings* s, String text);
void AddLine(TStrings* s, String text)
{
s->Add(text);
}
//in exe
AddLine(Memo1->Lines, "Text")
А так не получится?
extern "C" __declspec(dllexport) void AddLine(TStrings* s, String text);
void AddLine(TStrings* s, String text)
{
s->Add(text);
}
//in exe
AddLine(Memo1->Lines, "Text")
Может и получиться, но учитывая, что при сборке без пакетов Memo1->Lines и s представляют собой разные куски кода, результат не может быть гарантирован на все 100%
А так не получится?
extern "C" __declspec(dllexport) void AddLine(TStrings* s, String text);
void AddLine(TStrings* s, String text)
{
s->Add(text);
}
//in exe
AddLine(Memo1->Lines, "Text")
Спасибо за содержательный ответ, поскольку у меня мало опыта, ваш пример кода это то что мне было нужно. Как минимум есть направление куда копать.
Спасибо за содержательный ответ, поскольку у меня мало опыта, ваш пример кода это то что мне было нужно. Как минимум есть направление куда копать.
Не за что.
Внимательно прочитай, что dll-wizard генерит:
// Important note about DLL memory management when your DLL uses the
// static version of the RunTime Library:
//
// If your DLL exports any functions that pass String objects (or structs/
// classes containing nested Strings) as parameter or function results,
// you will need to add the library MEMMGR.LIB to both the DLL project and
// any other projects that use the DLL. You will also need to use MEMMGR.LIB
// if any other projects which use the DLL will be performing new or delete
// operations on any non-TObject-derived classes which are exported from the
// DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
// EXE's to use the BORLNDMM.DLL as their memory manager. In these cases,
// the file BORLNDMM.DLL should be deployed along with your DLL.
//
// To avoid using BORLNDMM.DLL, pass string information using "char *" or
// ShortString parameters.
//
// If your DLL uses the dynamic version of the RTL, you do not need to
// explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------
#pragma argsused
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
return 1;
}
Спасибо за содержательный ответ, поскольку у меня мало опыта, ваш пример кода это то что мне было нужно. Как минимум есть направление куда копать.
Прислушайся к тому, что говорит smartsoft.
Этот код некорректен и потенциально опасен.
Лучше передавать не просто указатель на экземпляр классо, но ещё и указатель на метод (Add) этого класса.
А я ничего не говорю, здесь одно другому не мешает, обязательно проверю флажок в настройках. Я ведь больше всех заинтересован в положительном результате!
Просто конкретный пример - участок кода всегда красноречиво говорит за себя, ведь программистам читать код удобнее (для меня понятнее) чем читать его словесное описание. К тому же иногда словесное описание можно понять-истолковать по разному.
Передать указатель на функцию - это понятно, а как указатель на метод?
Прислушайся к тому, что говорит smartsoft.
Этот код некорректен и потенциально опасен.
Лучше передавать не просто указатель на экземпляр классо, но ещё и указатель на метод (Add) этого класса.
Если уж точно, то при статической компиляции dll действительно адрес (TStrings*) s будет неверный.
Но при динамической загрузке dll все указатели будут корректны.
Если уж точно, то при статической компиляции dll действительно адрес (TStrings*) s будет неверный.
Но при динамической загрузке dll все указатели будут корректны.
Повторюсь еще раз: дело не в статической или динамической загрузке DLL, а в компиляции с пакетами или без. Не надо путать терминологию.
Повторюсь еще раз: дело не в статической или динамической загрузке DLL, а в компиляции с пакетами или без. Не надо путать терминологию.
Тогда если можно аргументы, факты. При чем здесь bpl, если они только в билдере и дельфе.
А как тогда дело будет обстоять в других языках?:)
Тогда если можно аргументы, факты. При чем здесь bpl, если они только в билдере и дельфе.
А как тогда дело будет обстоять в других языках?:)
Так TStrings тоже в Билдере и Дельфи. Дополнительная информация в BPL Борланда - своеобразная замена "name mangling" в C++, компиляторах, позволяющих экспортировать методы классов из DLL.
Другие языки программирования вроде не позволяют экспортировать именно методы классов из DLL. В полноценных ОО-средах, вроде JVM или CLR, подобной проблемы не существует. Они изначально предусматривают штатные средства экспорта методов классов.
Если уж точно, то при статической компиляции dll действительно адрес (TStrings*) s будет неверный.
Но при динамической загрузке dll все указатели будут корректны.
Что ты подразумеваешь под "статической компиляции dll"?
Возможно, ты имел в виду статическое подключение и динамическое. Тогда не понятно, почему "адрес будет неверный".
Дело не в указателях, а в том, что реализация класса в программе и в библиотеке могут отличаться, т.о. метод Add класса TString из программы может делать совсем не то, что метод Add класса TString из библиотеки. Если это метод виртуальный то, вообще, такое начнется...
Пример.
Мы сделали такую DLL с одной версией VCL.
Потом начали писать программу уже с другой версией VCL, в которой класс TString несколько изменили (в этом и суть новой библиотеки - дорабатывать старую): добавили или поменяли порядок следования виртуальных методов или изменили порядок наследования.
Но в нашей DLL жестко забито по какому смещению в таблице виртуальных методов мы должны взять адрес метода Add. А пришедший указатель указывает на новый класс TString, а там по этому смещению может быть записан другого метода. И в результате вместо Add вызовется SystemAnnihilation.
И пример с новой VCL не единственный, такая же беда случится, если программа и DLL будут собраны с различными параметрами (к примеру, параметры оптимизации).
Вообще то, хорошее правило: не передавать в DLL указатели на классы, только на структуры данных (т.е. данные без обработчиков), тогда библиотека собранная например в Builder, может быть использована например с программами на VC++.
Так TStrings тоже в Билдере и Дельфи. Дополнительная информация в BPL Борланда - своеобразная замена "name mangling" в C++, компиляторах, позволяющих экспортировать методы классов из DLL.
Это ясно, хидер класса должен быть и в программе и в dll.
Но можно передать указатель на любой другой класс, который описан в и программе и dll, и не обязательно класс VCL.
Почему же указатель будет недостоверный ??
Это ясно, хидер класса должен быть и в программе и в dll.
Но можно передать указатель на любой другой класс, который описан в и программе и dll, и не обязательно класс VCL.
Если методы не виртуальные, у тебя будет два экземпляра кода класса: один в программе, другой - в библиотеке. Это будут два разных указателя. И не факт, что они будут ссылаться на код, который делает одно и то же с данными, расположенными по одним и тем же адресам.
С виртуальными методами проще - достаточно, чтобы совпадало число точек входа VMT и прототипы самих методов. Ну, и соглашения по вызову, разумеется.
Что ты подразумеваешь под "статической компиляции dll"?
Возможно, ты имел в виду статическое подключение и динамическое. Тогда не понятно, почему "адрес будет неверный".
Да именно. Договорились, адрес верный в обоих случаях, тогда далее...
Дело не в указателях, а в том, что реализация класса в программе и в библиотеке могут отличаться, т.о. метод Add класса TString из программы может делать совсем не то, что метод Add класса TString из библиотеки. Если это метод виртуальный то, вообще, такое начнется...
Пример.
Мы сделали такую DLL с одной версией VCL.
Потом начали писать программу уже с другой версией VCL, в которой класс TString несколько изменили (в этом и суть новой библиотеки - дорабатывать старую): добавили или поменяли порядок следования виртуальных методов или изменили порядок наследования.
Но в нашей DLL жестко забито по какому смещению в таблице виртуальных методов мы должны взять адрес метода Add. А пришедший указатель указывает на новый класс TString, а там по этому смещению может быть записан другого метода. И в результате
вместо Add вызовется SystemAnnihilation.
Согласен 150%...
И пример с новой VCL не единственный, такая же беда случится, если программа и DLL будут собраны с различными параметрами (к примеру, параметры оптимизации).
Вообще то, хорошее правило: не передавать в DLL указатели на классы, только на структуры данных (т.е. данные без обработчиков), тогда библиотека собранная например в Builder, может быть использована например с программами на VC++.
Если уж мы используем VCL классы, то какие уж тут VC++..
Все подводные камни понятны, но если хидер класса и в программе и в библиотеке один. Это означает версия и реализация класса одинаковы и для проги и для библиотеки. Почему же некорректно и опасно передавать указатель на класс.??
Это же не детский сад не делай это, бо опасно!!!
Мой же вопрос такой, если я, знаю и учитываю все эти камни. Не должен(опасно!) передавать указатель на класс, потому что...
Может и получиться, но учитывая, что при сборке без пакетов Memo1->Lines и s представляют собой разные куски кода, результат не может быть гарантирован на все 100%
Передать указатель на функцию - это понятно, а как указатель на метод?
Пример:
typedef int(TStrings::* t_Add)(String);
extern "C" __declspec(dllexport) void AddLine(TStrings* s, String text);
void AddLine(t_Add Add, TStrings* s, String text)
{
(s->*Add)(text);
}
//in exe
AddLine(TStrings::Add, Memo1->Lines, "Text")
Если уж мы используем VCL классы, то какие уж тут VC++..
Ну а кто мешает использовать dll написаную в одной IDE (с использованием одного языка, одной библиотеки) при программировании в другой IDE (на другом языке с использованием других библиотек)?
Ты же используешь kernel32.dll, уверяю, что она написана не в BCB.
Все подводные камни понятны, но если хидер класса и в программе и в библиотеке один. Это означает версия и реализация класса одинаковы и для проги и для библиотеки. Почему же некорректно и опасно передавать указатель на класс.??
Это же не детский сад не делай это, бо опасно!!!
Нет, это не означает, что реализация одинакова по нескольким причинам:
1) обычно в заголовочном файле класс описывается, а реализуется он в другом месте;
2) реализация может отличаться в зависимости от параметров компиляции, даже если программный код одинаков.
Ты можешь не учесть всех этих "подводных камней", да и зачем создавать потенциальноопасную ситуацию.
Почему опасно и некорректно я уже на пальцах объяснял. Попробую более научный подход. :)
C++ в отличие от С обладает повышенной типовой безопасностью и это связано с тем, что в С++ появидись более сложные типы - классы.
Механизм же DLL не обладает таковой типовой безопасностью, он не "заточен" под ООП. Поэтому следует исскуственно поднимать эту самую безопасность.
Если в нашем примере передавать лишь указатель на класс, то получается такая схема преобразования:
TString* -> void* -> TString'*
(штрих я поставил специально для обозначения неидентичности обоих TString)
При приведении к void* нарушается типовая безопасность, это уже неоднократно здесь обсуждалось с моим участием.
Нет, это не означает, что реализация одинакова по нескольким причинам:
1) обычно в заголовочном файле класс описывается, а реализуется он в другом месте;
2) реализация может отличаться в зависимости от параметров компиляции, даже если программный код одинаков.
Ты можешь не учесть всех этих "подводных камней", да и зачем создавать потенциальноопасную ситуацию.
Нет, я все же соблюдаю все правила и условия и использую один и те же h, cpp или obj или pas файлы в обоих случаях.
Параметры компиляции тоже одинаковые. Хотя наверное так нельзя сказать.;-)
И даже в этом случае реализация отличается???!!!
Почему опасно и некорректно я уже на пальцах объяснял. Попробую более научный подход.
C++ в отличие от С обладает повышенной типовой безопасностью и это связано с тем, что в С++ появидись более сложные типы - классы.
Механизм же DLL не обладает таковой типовой безопасностью, он не "заточен" под ООП. Поэтому следует исскуственно поднимать эту самую безопасность.
Если в нашем примере передавать лишь указатель на класс, то получается такая схема преобразования:
TString* -> void* -> TString'*
(штрих я поставил специально для обозначения неидентичности обоих TString)
При приведении к void* нарушается типовая безопасность, это уже неоднократно здесь обсуждалось с моим участием
По поводу научного подхода..
Но ведь приводим же TString* к void* и void* разыменовываем как TString'* и динамич. приведение типов используем...
Нарушаем типовую безопасность повсеместно... ;-) Хорошо что ANSI и компилятор позволяет это делать.
Но мой вопрос ко всему этому, самое интересное, не относился..
Каким местом в этой теме приложить компиляцию с пакетами и без??..
Вот тут непонятно..
Прошу прощения за назойливость.
Нет, я все же соблюдаю все правила и условия и использую один и те же h, cpp или obj или pas файлы в обоих случаях.
Параметры компиляции тоже одинаковые. Хотя наверное так нельзя сказать.;-)
И даже в этом случае реализация отличается???!!!
А вот фиг его знает...
Сегодня ты скомпилировал DLL, а завтра забыл про параметры или переустановил версию компилятора или еще что-нибудь и абзац! Причину ошибки будешь искать долго, гарантирую.
По поводу научного подхода..
Но ведь приводим же TString* к void* и void* разыменовываем как TString'* и динамич. приведение типов используем...
Нарушаем типовую безопасность повсеместно... ;-) Хорошо что ANSI и компилятор позволяет это делать.
Ага нарушаеТЕ, и я бы руки обрывал за такое. :)
Это не раз обсуждалось, пройдись поиском по форуму по ключам Green и void*.
Вот к примеру:
http://forum.codenet.ru/showthread.php?s=&threadid=14158
Каким местом в этой теме приложить компиляцию с пакетами и без??..
Вот тут непонятно..
smartsoft, видимо, имел в виду динамическое подключение библиотеки VCL. В этом случае реализация TString, наверное, должна быть в каком нибудь из bpl. Т.о. и программа и DLL будут ссылаться на реализацию к третему модулю (bpl) и неоднозначности не должно быть. Но так ли это будет на самом деле я не знаю, т.к. не знаю внутренностей VCL.
В этом случае реализация TString, наверное, должна быть в каком нибудь из bpl. Т.о. и программа и DLL будут ссылаться на реализацию к третему модулю (bpl) и неоднозначности не должно быть. Но так ли это будет на самом деле я не знаю, т.к. не знаю внутренностей VCL.
Да, так оно и будет. Именно для этого и предназначены BPL в Дельфи/Билдере.
Могу даже конкретно сказать: при использовании стандартных пакетов реализация TStrings будет сидеть в vcl.bpl (или vclxx.bpl, где xx - номер версии).
Если дать команду tdump <имя bpl> <имя файла отчета>, в файл отчета будет записана полная информация по BPL, в том числе и точки экспорта. Кстати, там же можно увидеть, как компиляторы Borland осуществляют маскирование имен.