ПЗ
>Про COM и формат представления
http://www.geocities.com/svi37/cyber/delphi9/iimplementation.html
>По-моему, экземпляры класса в машкоде одинаково представляются
если бы тк было, не надо было б придумывать СОМ
*vmr #28
Во, я всё никак не мог собраться с мыслями чтобы это сазать :) Именно что на бинарном уровне.
Дык, про COM там ничего нового не написано. Указатель на класс по-сути указывает на его VMT (4 байта), а дальше перечисляются поля и невиртуальные методы класса. В сях, ЕМНИП, тоже первым идет указатель на VMT (4 байта), а потом... суп с котом :-))) Что еще можно запихать после ук.VMT кроме полей и методов? Нинаю. Седни попробовал простейший случай с одним виртуальным методом - пока безуспешно. Возможно я чего-то в синтаксисе напутал. Много воды утекло :-))
Кстати, в MS SDK есть утилита EDITBIN.EXE, которая вроде умеет конвертировать OMF-формат объектных файлов в COFF-формат. Может, сюда покурить?
Порядок следования методов в этом VMT. Формат в 2005 студии и 2008 отличается -- тема на форуме уже была (жаль поиск не рулит)
Глаза боятся - руки делают. Сегодняшний эксперимент увенчался успехом.
Имеем простейший класс на Делфи, загнанный в DLL. Экспортируемая функция возвращает ссылку на экземпляр этого класса:
library MyDLL;
uses
SysUtils,
Classes;
{$R *.res}
type
TFoo= class
public
function AFoo:Char;virtual;cdecl;
end;
var Foo:TFoo;
PFoo:^TFoo;
function TFoo.AFoo:Char;
begin
Result:='A';
end;
function Func1:Pointer;
begin
PFoo:=@Foo;
Result:=Foo;
WriteLn(PFoo^.AFoo);
end;
exports
Func1;
begin
Foo:=TFoo.Create;
end.
Клиентская программа на MSVC.NET (эрзац 3dsMAX) загружает DLL, получает ссылку на объект и вызывает его метод:
#include "stdafx.h"
class CFoo
{
public:
virtual char AFoo()=0;
};
typedef void* (__cdecl* PFUNC)();
int main(int argc, char* argv[])
{
printf("Hello World!\n");
HMODULE hLibrary=LoadLibrary("MyDLL.Dll");
PFUNC Func1= (PFUNC) GetProcAddress(hLibrary,"Func1");
CFoo* Foo=(CFoo*)Func1();
char ch=Foo->AFoo();
printf(&ch);
FreeLibrary(hLibrary);
return 0;
}
Вместо printf лучше было бы наверное COUT, но я уже забыл как им пользоваться. В любом случае, буква "А" печатается, прога не вылетает и в дебаге все вызовы отслеживаются.
Будем двигаться дальше в сторону усложнения экспериментов...
>Будем двигаться дальше в сторону усложнения экспериментов...
type TFoo= class public function BAFoo:Char;virtual;cdecl; function AFoo:Char;virtual;cdecl; function BFoo:Char;virtual;cdecl; end;
нашел этот топик: http://www.gamedev.ru/code/forum/?id=80323
ПЗ
Вообще-то идея обратная - нужно из Dlphi вызывать Cpp классы :) Ибо в этом заключается сложность - из Delphi юзать max sdk, которое представленно классами.
Провел следующий успешный эксперимент:
TFoo= class
public
function AFoo:Char;virtual;cdecl;
function BFoo:Char;virtual;cdecl;
end;
Он же:
class CFoo
{
public:
virtual char AFoo()=0;
virtual char BFoo()=0;
};
По-прежнему работает. Осталось понять, что делать с невиртуальными методами.
Зачем нужно из делфи вызывать сишные классы, я не понял. Классы сидят в dll плагина, который мы (я) хотим написать на делфи. Вызывает их 3ds, написанная на MSVC. Именно это я и пытаюсь смоделировать. Начало успешное. Теперь надо переписать заголовки основных классов SDK с С на делфи, и пытаться компоновать минимально-достаточную dll. Если бы мы тут перестали пугать друг друга жуткими страшилками, а начали своместно думать над задачей, толку было бы гораздо больше.
ПЗ
>Провел следующий успешный эксперимент:
Че ты тратитиш лабораторный инвертарь на пустые Экспэрименты? :)
Тебе уже сказали что нужно тестировать....
>Теперь надо переписать заголовки основных классов SDK с С на делфи
Каждую новую версию макса/дельфы будеш переписывать/перепроверять?
Просто стемное это дело - гадать гадать порядок расположения вирт. методов
Тем более что никто его не гарантирует.....
Самое простое - сделать один раз прокси-длл и не парить себе мозги в дальнейшем
ПЗ
>Зачем нужно из делфи вызывать сишные классы, я не понял. Классы сидят в dll плагина, который мы (я) хотим написать на делфи.
Мы, мы. Хотим и пишем :)
Класс который в dll - это логика экспортера. Всего лишь.
Повторяю: реализация Max SDK сидит в dll-ках ядра макса в виде сишных классов. Их и надо использовать, это и есть главная задача. Сам плагин мапит эти классы и использует их. В этом и есть суть max плагина - max загружает его, а тот при загрузке получает ссылки на внутримаксовские объекты, и использует их для получении инфы о сцене.
Vmr: В МАКСЕ отсутствует обратная совместимость. На чем бы ты не написал плагин, с каждой новой версией его надо переделывать. Работоспособность плагинов 7-й версии в 8-й не гарантирована. Держать две DLL на один плагин не рационально. Вместо прокси у Coriolis практически готовый плагин на C++. Подключение к нему доп. модуля на пасе во-первых, также не универсально, во-вторых, расточительно по ресурсам, а в третьих, не дает никакого выигрыша программисту Delphi. Оставим этот вариант на крайний случай, если все другие способы не дадут реззультата.
Coriolis:Если вызовы пасовских классов сишным клиентом идут, то и в обратную сторону никуда не денутся. DLL не DCU. Я иду последовательно. Сейчас проблема в том, как реализовать хотя бы минимально-необходимую иерархию из SDK на пасе, чтобы оно загрузилось и написало «Hello World». Дойдем до этого, будем думать что дальше.
Если нет интереса, могу перестать докучать своими глупостями…
ПЗ
>Если нет интереса, могу перестать докучать своими глупостями…
Не, что ты, продолжай, ты не докучаешь, и это не глупости. Было б мне не интересно - я бы не отвечал.
>Работоспособность плагинов 7-й версии в 8-й не гарантирована.
Есессно SDK-то разный. А ты думал? Под каждую версию макса заново компилить и перепесывать что-то местами надо. Это данность свыше. :)
>Держать две DLL на один плагин не рационально.
??? Каким местом не рационально? :) _Может быть_ немного неудобно (типа два файдла, а не один - omg это гемор), но, знаешь ли... какая разница? :)
>Вместо прокси у Coriolis практически готовый плагин на C++.
Нет, ну а как ты иначе представляешь прокси? :) Это и есть плагин, который переадресует вызовы на Delphi DLL.
>Подключение к нему доп. модуля на пасе во-первых, также не универсально
Что ты хочешь универсального? Не понял мысль. Ну да, при смене версии надо будет перекомпилить обе части - но это уж совсем крайний случай - смены версии. Здесь универсальности изначально в AutoDesc не планировалось, дак откуда она возьмется у меня? Или у тебя, с твоим методом прямого вызова?
> во-вторых, расточительно по ресурсам
Каким местом? Из-за лишнего вызова? Ерунда полная этот вызов. Это ничто можно сказать. На производительность он повлияет конечно, НО только при огромнейших моделях. Ради чистого кодинга на Delphi лично я готов на это забить. Я думаю про ресы ты сказал ради красного словца ;)
>а в третьих, не дает никакого выигрыша программисту Delphi
Ну ты это, сосем уж наехал :) Приехали :) А как тебе "теперь можно писать плагин экспорта на своём любимом языке"? Это разве не засчитывается за мега-бонус? Я запускаю Delphi, открываю проект и пишу плагин экспорта для макса, на выходе получаю bin код, могу собрать инсталяху - получаю полностью готовый плагин, без всяких max скриптов и cpp. Получаю скорость работы бинарного кода, возможность строить интерфейс какой хочу и т.д. - короче все + бинарника.
И потом, "не даёт никакого выигрыша" по сравнению с чем? Может быть ты имеешь в виду то что у меня описана небольшая часть СДК, а не полностью? На самом деле переписывание хидеров Max SDK с cpp на Delphi - та еще работка, у меня местами некоторые функции вообще отрабатывают полностью на Cpp части плагина, чтобы не делать лишних вызовов на Delphi часть. Например, блок вычленения повершинных нормалей - там довольно большой кусок, учитываются всякие модификаторы (типа Normal Edit), в итоге нормали передаются идеально. Но этот кусок юзает тучу максовского кода, всё это придется переписывать на Delphi - а смысл? Это код который пишется один раз и не меняется вообще никогда (в пределах одной версии). Т.е. у меня не просто обертка - у меня там внутри есть логика, которую замучаешься переводить на Delphi - понадобится действительно переводить хидеры всего SDK.
>Если вызовы пасовских классов сишным клиентом идут, то и в обратную сторону никуда не денутся. DLL не DCU.
Это понятно, ты же вроде как сделал уже, нет? (хотя пример *vmr ты так и не попробовал, мне тоже интересно - как оно буит.
>Я иду последовательно. Сейчас проблема в том, как реализовать хотя бы минимально-необходимую иерархию из SDK на пасе, чтобы оно загрузилось и написало «Hello World». Дойдем до этого, будем думать что дальше.
Да даже если не получится - можно использовать proxy dll как это сделал я - это вообще не проблема, как ты понять не можешь. Несколько прямых вызово функций - и всё.
Самое сложное и интересное - это на паскале описать интерфейсы, примапить их к реализациям классов, созданным на cpp - и чтобы это заработало.
Вот это и есть главная трабла, я не стал её решать так как ты хочешь а написал врапперы на каждый нужный класс.
Типа, имеем созданный на cpp класс, имеем его хидер (в смысле знаем какая функция где).
Нужно создать (а точнее - уметь создавать автоматом по хидеру) конструкцию на pascal'е, которая сможет послужить враппером для этого класса.
В качестве основы можно использовать class, а можно и старый тип - object. У меня правда нет описания vmt, надо копать в эту сторону.
Главный вопрос (пока, и имхо) это меняет ли паскалевский компилер порядок функций в кслассе. Если менят - то всё бестолку - не отгадаешь как что ляжет.
В любом случае - согласись, манипуляция vmt - это хардкор, как ни крути. А ты еще пальцем в меня тыкаешь, мол не универсально. Я-то как раз за пределы чистого pascal и чистого C++ не выходил, шаманством не занимался. У меня скомпилешь любым Delphi компилером - и всё заработает.
Хотелось бы ваработать универсальное решение, честно, это было-бы красиво и пригодилось бы не только для Max плагина. Можно было б писать mod к HL2, например :) Да много продуктов сейчас с SDK на cpp. Но такое решение будет только под конкретную версию студии.
Да нифига ты реальный "боевой" плагин на делфи через c++ посредника не сможешь писать. Все время надо будет расширять, дополнять и изменять твой proxy CPP-SDK на каждый чих. Ну и какой выигрыш программеру, который не знает С? Получается плагин, который надо на двух языках сразу писать и двумя компилерами компилить. Тогда уж проще целиком на CPP, и не чесать левой пяткой правое ухо. Вот что я имел в виду выше.
Подключение лишней DLL, переадресация вызовов, получение указателей на внутренние процедуры и т.д. – все это время, память и ресурсы. По нынешним мощностям конечно не существенно, но стилистически не очень красиво. Посему, согласись, куда заманчивее было бы написать целиком всю DLL на пасе. Попробовать хотя бы стоит. Вариант
type TFoo= class public function BAFoo:Char;virtual;cdecl; function AFoo:Char;virtual;cdecl; function BFoo:Char;virtual;cdecl; end;
только что попробовал, все работает. Так что с VMT проблем нет, всё по-честному. Проблемы есть с не-VMT :-) В MAX SDK полно не-виртуальных методов. Их MAX сможет вызывать из пас-DLL? Или может вообще на них забить? Есть мысли?
ПЗ
> В MAX SDK полно не-виртуальных методов. Их MAX сможет вызывать из пас-DLL? Или может вообще на них забить? Есть мысли?
Импортируеш/вызываешь как обычные функции
>Все время надо будет расширять, дополнять и изменять твой proxy CPP-SDK на каждый чих
Зато ты знаеш что ты меняеш и как оно в последствии будет работать
>Попробовать хотя бы стоит
В том то и дело, что будут танцы с бубном: сдесь не работает, почему - хз; там отвалилось - причина неизвестна; сдесь в этой версии работает, в той - нет, писать дефайны?
Тема в архиве.
Ремонт ноутбуков Компонентный ремонт ноутбуков в Вологде remchip.ru |