ПЗ
>Да нифига ты реальный "боевой" плагин на делфи через c++ посредника не сможешь писать.
Да, спорить не могу - еще не писал плагин "реальный боевой". Однако, в примере вполне рабочий плагин, который экспортит всё как надо, всё 1:1 как в максе. Анимации в этом плагине нет, но экспортить её можно - посмотри описание возможностей (да и в плагине она выгружается в текстовом виде).
Короче, к вопросу сможешь/не сможешь я готов вернуться через пол-года, когда продолжу писать свой двиг :) Сильно сомневаюсь что буду что-то переделывать в существующем, правда. А вот из дописывания - наверно с шойдерами что-то надо будет сделать, вроде в максе есть такой модификатор. Однако, я не позиционирую это SDK как профессиональную тулзу. Я хочу помочь начинающим Delphi программистам, которые решили написать что-то своё и уткнулусь в проблему экспорта из макса. А для начинающего этого SDK за глаза. Если хочешь - можем продолжить спор в направлении "это SDK фигня, там нет того-то того-то того-то" - я почерпну для себя много инфы ;)
>Подключение лишней DLL, переадресация вызовов, получение указателей на внутренние процедуры и т.д. – все это время, память и ресурсы.
Еще раз утверждаю - это всё фигня :) Это не время, это не память, это не ресурсы - это ничто для современных (и не очень) компов. :)
>По нынешним мощностям конечно не существенно,
ну и я о чем, если сам понимаешь - что заладил-то - "затраты, затраты"?
>но стилистически не очень красиво.
К чёрту стилистику - это 100% стабильно работает, причем вся т.н. "некрасивость" от впечатлительных идеалистов-программистов спрятана - на дельфи всё мягко и пушисто (что и требовалось).
>Посему, согласись, куда заманчивее было бы написать целиком всю DLL на пасе. Попробовать хотя бы стоит.
Соглашусь что заманчиво, но не из-за твоих доводов, а просто из-за того что работы системному программеру вроде как меньше - для прикладника один фиг одианоково будет выглядеть.
Хоть *vmr уверен что это всё утопия, я бы попробовал. Времени только вот нет, к сожалению.
Vmr*: Оценил остроумие. А по делу есть мысли? Я не могу позвонить в автодеск и попросить их импортировать методы моего плагина как обычные функции.
Coriolis: Начинающему программисту на Delphi ты поможешь только тем, что заставишь его учить С++. Первое, с чего надо начинать написание «боевого» плагина – изучить исходники твоего SDK. Потом ставить студию и начинать затачивать их под себя. Если возможно написать все одной DLL на одном Delphi, почему бы не попробовать? Если мы убедимся, что это невозможно, тогда пойдем дальше. Одна DLL хуже чем две?
Есть предложение отказаться от терминов «наезд» и т.п. Я сюда не пиписьками меряться пришел и наезжать ни на кого не собираюсь. У меня тоже мало времени. На работе комп запаролен и программировать на нем нельзя. А дома я бываю 2 часа в день и данным вопросом занимаюсь на интерес.
ПЗ
>возможно написать все одной DLL на одном Delphi, почему бы не попробовать?
Это будет похоже на взлом черного ящика....
Ты отталкиваешся от примитивных экспериментов на классах в три метода.... и удивляешся почему так не делают...
Побробуй сначала сделать какой-либо РЕАЛЬНЫЙ порт, сразу подобные желания отпадут....
Зачем писать порт на _недокументированный_ интерфейс (бинарное представление классов), когда есть хорошо изученная штука как С++?
Жалко лишней ДЛЛ-ки?
>Есть предложение отказаться от терминов «наезд» и т.п.
Да я ж так, по доброму :) Шутя.
>Начинающему программисту на Delphi ты поможешь только тем, что заставишь его учить С++. Первое, с чего надо начинать написание «боевого» плагина – изучить исходники твоего SDK.
Зачем ему исходняки СДК? Я же написал - новичку функционала за глаза. Ненужна ему студия.
>Зачем ему исходняки СДК?
Я на всякий случай напомню название твоей статьи: "Delphi 3DSMAX SDK for ...."
>Я же написал - новичку функционала за глаза
Очень спорное заявление.
>Ты отталкиваешся от примитивных экспериментов на классах в три метода....
Понится, кто-то тельняху рвал, что они не заработают.
>Зачем писать порт на _недокументированный_ интерфейс
Я пока не использовал ни одной недокументированной функции.
Очень жаль, что не получилось найти взаимопонимание. Конструктивные советы были бы куда полезнее. Ну что ж, может оно и к лучшему. Буду продолжать потихоньку эксперименты, авось куда выгребу...
ПЗ
>Понится, кто-то тельняху рвал, что они не заработают.
Oo
>Я пока не использовал ни одной недокументированной функции.
Ты использовал недокументированную VMT
>Конструктивные советы были бы куда полезнее
Но какой сдесь совет можно дать? :)
>Буду продолжать потихоньку эксперименты, авось куда выгребу...
А выгребеш ты бесценный опыт, да. Но увы еще и потратиш уйму времени....
>>Зачем ему исходняки СДК?
>Я на всякий случай напомню название твоей статьи: "Delphi 3DSMAX SDK for ...."
Ты чего-то не понимаешь :) Еще раз спрашиваю - зачем пользователю моего SDK исходняки max SDK и ковыряние в них? Его плагин будет компилиться и работать и без SDK :) Из max SDK ему понадобится только справка.
>>Я же написал - новичку функционала за глаза
>Очень спорное заявление.
Ну дык оспорь :) А то просто так говорить все могут. :)
>Очень жаль, что не получилось найти взаимопонимание. Конструктивные советы были бы куда полезнее. Ну что ж, может оно и к лучшему. Буду продолжать потихоньку эксперименты, авось куда выгребу...
Я тебе имхо дал конструктивный совет - забей на вызов Delphi класса из cpp. Займись вызовом реализации Cpp класса из Delphi - это намного важней. И не принимай всё так в штыки.
Передо мной стоит задача написать полноценный плагин, для моделлеров (не игровых) занимающихся фотореалистичным рендером. Писать хочется на дельфи :). Но "чесать пяткой ухо", как было сказано выше, желания абсолютно не какого :).
Поэтому хотелось бы какнибудь поспособствовать решению задачи поставленной ПЗ, хоть и придется плагин на сипипи писать :(.
Мои контакты:
icq:278-110-470
мыло: venumsl {sobaаkaа] gmail ( toоchkaа } ком
Ну есессно, для фотореалистичного рендера этого СДК мало. :)
>Но "чесать пяткой ухо", как было сказано выше, желания абсолютно не какого :).
Да нормальный это способ блин, ничего извращенного. Всё что заявлено в статье - работает "на ура". Лишь бы словом ярким броситься блин.
Я именно Coriolis-SDK имел в виду. Не хотел больше докучать, но специально для нового интересанта, еще одна ремарка. То, что юзеру придется копаться в SDK Autodesk и так понятно, без этого вообще о каких плагинах речь? По Coriolis- SDK, если угодно, навскидку: DllEntry.cpp
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { hInstance = hinstDLL; // Hang on to this DLL's instance handle. if (!controlsInit) { controlsInit = TRUE; InitCustomControls(hInstance); // Initialize MAX's custom controls InitCommonControls(); // Initialize Win95 controls } return TRUE; }
Читаем хелп Autodesk`SDK на InitCustomControls – “This method has been deprecated. Plugins used to be required to call this method from their DllMain in order to initialize 3ds Max custom controls used by the plugin. Plugins no longer need to call this method from their DllMain or other code. The custom controls are initialized by 3ds Max automatically.”
Едем дальше - Required DLL Functions:
BOOL WINAPI DllMain(HINSTANCE hinstDLL,ULONG fdwReason,LPVOID lpvReserved) { switch(fdwReason) { case DLL_PROCESS_ATTACH: hInstance = hinstDLL; DisableThreadLibraryCalls(hInstance); break; } return(TRUE); }
Без вызова DisableThreadLibraryCalls Coriolis`s SDK-Proxy-Dll-Plugin в двух попытках из трех вызывает крэш 3ds при загрузке. У меня, по-крайней мере. И это только то, что всплыло сразу же, навскидку. А дальше, как и в любой уважающей себя программе (включая саму 3dsMAX), пойдут менее очевидные баги и усовершенствования, которые периодически будут всплывать и требовать устранения. Это нормально. Ненормально то, что для этого надо будет вникать в тонкости кода самой Proxy на С++ и держать под рукой соответствующий инструментарий. А тем временем, на выходе уже новая версия 3dsMAX и ее SDK, где вообще все может стать по-другому и опять придется править, менять, дополнять.
Я, тем временем, продолжаю опыты. Вчера, наконец, удалось сваять на Delphi PLUGIN.DLU, которую 3dsMAX заглатывает без Access Violation. Вместо ClassDesc2 пока возвращает nil. Следующая остановка – реализация ClassDesc2 на Delphi. Дежурная проблема на сегодня – как МАХ вызывает НЕВИРТУАЛЬНЫЕ методы объекта из DLL? Умные статьи по ООП, DLL и С++, вообще-то делать это запрещают! КАК?!
ЗЫ. К размышлению: http://www.citforum.ru/programming/delphi/vcpp_classes_in_delphi/
ПЗ, у тебя точно SDK к восьмой студии? Тестовый плагин (который в SDK в качестве примра) тестила куча народу - всё окей, никаких вылетов. Может ты намудрил где? Версия дельфи у тебя какая? Патч последний к SDK и на сам 3DSMax стоит?
Потом, код корый в DllEntry.cpp - сгенерила сама SDK, через вижуал студию. Когда ставишь SDK в студии появляется такой тип проекта (с мастером создания) - 3dsMax export plugin.
Потом, это всё системные вещи, Delphi программер должен морочиться только на счет своего SuperFormat'а и структуры классов MaxStudio, как их подружить вместе.
PS за ссылку спасибо, оч интересно, тоже буду курить в эту тему.
Заинтересованным лицам. Требуется помощь для продолжения экспериментов.
1. За основу взят C++ -плагин http://www.gamedev.ru/users/wat/forum/?id=57426
2. Методом братьев Монгольфье, все лишнее выброшено за борт: LibClassDesc возвращает ClassDesc вместо ClassDesc2. Метод ClassDesc.Create возвращает NULL, все методы перегружены, в каждый вставлен MessageBox для контроля последовательности вызовов при загрузке плагина. Последовательность следующая:
ClassDesc.SuperClassID ClassDesc.ClassID ClassDesc.SuperClassID ClassDesc.IsPublic ClassDesc.ClassID ClassDesc.ClassName ClassDesc.Category ClassDesc.InitialRollupState ClassDesc.NumActionTables =========================< Появление меню и окон 3dsMAX ClassDesc.Category ClassDesc.SuperClassID ClassDesc.ClassID ClassDesc.ClassName ClassDesc.ClassName ClassDesc.InternalName ClassDesc.InternalName ClassDesc.InternalName ClassDesc.Category ClassDesc.Category ClassDesc.Category =========================< Окончание загрузки 3dsMAX
3. Из покдлючаемых библиотек (Project Options\Linker\Input) изъяты все библиотеки 3ds SDK и оставлен только стандартный COMCTRL32.LIB. MyUtilityClassDesc объявлен независимым, самостоятельным классом, НЕ НАСЛЕДУЕМЫМ от ClassDesc из SDK:
class MyUtilityClassDesc { private: Tab<FPInterface*> interfaces; public: virtual void UnknownMethod1() {} virtual void UnknownMethod2() {} virtual ~MyUtilityClassDesc() {MessageBox(0,"ClassDesc.~ClassDesc","",MB_OK);} virtual int IsPublic() { MessageBox(0,"ClassDesc.IsPublic","",MB_OK); return 1; } virtual void * Create(BOOL loading = FALSE) { MessageBox(0,"ClassDesc.Create","",MB_OK); return NULL;//&theMyUtility; } int BeginCreate(Interface *i) {MessageBox(0,"ClassDesc.BeginCreate","",MB_OK); return 0;} int EndCreate(Interface *i) {MessageBox(0,"ClassDesc.EndCreate","",MB_OK); return 0;}; virtual const TCHAR * ClassName() { MessageBox(0,"ClassDesc.ClassName","",MB_OK); return "MyUtility"; } virtual SClass_ID SuperClassID() { MessageBox(0,"ClassDesc.SuperClassID","",MB_OK); return UTILITY_CLASS_ID; } virtual CClassID ClassID() { MessageBox(0,"ClassDesc.ClassID","",MB_OK); return cid;//MYUTILITY_CLASS_ID; } virtual const TCHAR * Category() { MessageBox(0,"ClassDesc.Category","",MB_OK); return "Utility"; } virtual BOOL OkToCreate(Interface *i) {MessageBox(0,"ClassDesc.OkToCreate","",MB_OK); return TRUE; } virtual BOOL HasClassParams() {MessageBox(0,"ClassDesc.HasClassParams","",MB_OK); return FALSE;} virtual void EditClassParams(HWND hParent) {MessageBox(0,"ClassDesc.EditClassParams","",MB_OK);} virtual void ResetClassParams(BOOL fileReset=FALSE) {MessageBox(0,"ClassDesc.ResetClassParams","",MB_OK);} virtual int NumActionTables() {MessageBox(0,"ClassDesc.NumActionTables","",MB_OK); return 0; } virtual ActionTable* GetActionTable(int i) {MessageBox(0,"ClassDesc.GetActionTable","",MB_OK); return NULL; } virtual BOOL IsManipulator() {MessageBox(0,"ClassDesc.IsManipulator","",MB_OK); return FALSE; } virtual BOOL CanManipulate(ReferenceTarget* hTarget) {MessageBox(0,"ClassDesc.CanManipulate","",MB_OK); return FALSE; } virtual BOOL CanManipulateNode(INode* pNode) {MessageBox(0,"ClassDesc.CanManipulateNode","",MB_OK); return FALSE; } virtual Manipulator* CreateManipulator( ReferenceTarget* hTarget, INode* pNode) {MessageBox(0,"ClassDesc.CreateManipulator","",MB_OK); return NULL; } virtual Manipulator* CreateManipulator(INode* pNode) {MessageBox(0,"ClassDesc.CreateManipulator2","",MB_OK); return NULL;} virtual BOOL NeedsToSave() {MessageBox(0,"ClassDesc.NeedsToSave","",MB_OK); return FALSE; } virtual IOResult Save(ISave *isave) {MessageBox(0,"ClassDesc.Save","",MB_OK); return IO_OK; } virtual IOResult Load(ILoad *iload) {MessageBox(0,"ClassDesc.Load","",MB_OK); return IO_OK; } virtual DWORD InitialRollupPageState() {MessageBox(0,"ClassDesc.InitialRollupPageState","",MB_OK); return 0x7fffffff;} // возвращает имя для MaxScript virtual const TCHAR * InternalName() { MessageBox(0,"ClassDesc.InternalName","",MB_OK); return _T("MyUtility"); } // возвращает hInstance модуля virtual HINSTANCE HInstance() { MessageBox(0,"ClassDesc.HInstance","",MB_OK); return hInstance; } virtual int NumParamBlockDescs() {MessageBox(0,"ClassDesc.NumParamBlockDescs","",MB_OK); return 0; } virtual ParamBlockDesc2* GetParamBlockDesc(int i) {MessageBox(0,"ClassDesc.GetParamBlockDesc","",MB_OK); return NULL; } virtual ParamBlockDesc2* GetParamBlockDescByID(BlockID id) {MessageBox(0,"ClassDesc.GetParamBlockDescByID","",MB_OK); return NULL; } virtual void AddParamBlockDesc(ParamBlockDesc2* pbd) {MessageBox(0,"ClassDesc.AddParamBlockDesc","",MB_OK); } virtual void BeginEditParams(IObjParam *ip, ReferenceMaker* obj, ULONG flags, Animatable *prev) {MessageBox(0,"ClassDesc.BeginEditParams","",MB_OK); } virtual void EndEditParams(IObjParam *ip, ReferenceMaker* obj, ULONG flags, Animatable *prev) {MessageBox(0,"ClassDesc.EndEditParams","",MB_OK); } virtual void InvalidateUI(ParamBlockDesc2* pbd) {MessageBox(0,"ClassDesc.InvalidateUI","",MB_OK); } virtual MCHAR* GetRsrcString(INT_PTR id){MessageBox(0,"ClassDesc.GetRsrcString","",MB_OK); return NULL;}; virtual void MakeAutoParamBlocks(ReferenceMaker* owner) {MessageBox(0,"ClassDesc.MakeAutoParamBlocks","",MB_OK); } virtual int NumParamMaps() {MessageBox(0,"ClassDesc.NumParamMaps","",MB_OK); return 0; } virtual IParamMap2* GetParamMap(int i) {MessageBox(0,"ClassDesc.GetParamMap","",MB_OK); return NULL; } virtual IParamMap2* GetParamMap(ParamBlockDesc2* pbd) {MessageBox(0,"ClassDesc.GetParamMap2","",MB_OK); return NULL; } virtual void SetUserDlgProc(ParamBlockDesc2* pbd, ParamMap2UserDlgProc* proc=NULL) {MessageBox(0,"ClassDesc.SetUserDlgProc","",MB_OK); } virtual ParamMap2UserDlgProc* GetUserDlgProc(ParamBlockDesc2* pbd) {MessageBox(0,"ClassDesc.GetUserDlgProc","",MB_OK); return NULL; } virtual bool DrawRepresentation(COLORREF bkColor, HDC hDC, Rect &rect) {MessageBox(0,"ClassDesc.DrawRepresentation","",MB_OK); return FALSE; } virtual int NumInterfaces() {MessageBox(0,"ClassDesc.NumInterfaces","",MB_OK); return 0; } virtual FPInterface* GetInterfaceAt(int i) {MessageBox(0,"ClassDesc.GetInterfaceAt","",MB_OK); return NULL; } virtual FPInterface* GetInterface(Interface_ID id){MessageBox(0,"ClassDesc.GetInterface","",MB_OK); return NULL; } virtual FPInterface* GetInterface(MCHAR* name){MessageBox(0,"ClassDesc.GetInterface2","",MB_OK); return NULL; } virtual void AddInterface(FPInterface* fpi){MessageBox(0,"ClassDesc.AddInterface","",MB_OK); }; virtual void ClearInterfaces() { MessageBox(0,"ClassDesc.ClearInterfaces","",MB_OK); } virtual Class_ID SubClassID() {MessageBox(0,"ClassDesc.SubClassID","",MB_OK); return Class_ID(); } virtual INT_PTR Execute(int cmd, ULONG_PTR arg1=0, ULONG_PTR arg2=0, ULONG_PTR arg3=0) {MessageBox(0,"ClassDesc.Execute","",MB_OK); return 0; } };
4. Для совместимости добавлены два пустых виртуальных метода, которые, очевидно, заменяют конструктор по-умолчанию и конструктор копий (в SDK не прописаны, но без них не работает). Последовательность вызовов осталась прежней, 3ds запускается, плагин загружается, название его отображается в свитке UTILITIES\MORE.
5. Создан аналогичный ClassDesc на Delphi:
ClassDesc=class {MaxHeapOperators} private interfaces:Tab; public destructor ClassDesc();virtual; function IsPublic():integer;virtual;cdecl; // Show this in create branch? function Creat(loading:Boolean=FALSE):Pointer;virtual;cdecl; // return a pointer to an instance of the class. function BeginCreate(i:IUnknown):Integer;virtual;cdecl; {return 0;} function EndCreate(i:IUnknown):Integer;virtual;cdecl; {return 0;} function ClassName():PAnsiChar;virtual;cdecl; function SuperClassID():SClass_ID;virtual;cdecl; function ClassID():MClass_ID;virtual;cdecl; function Category():PAnsiChar;virtual;cdecl; // primitive/spline/loft/ etc function OkToCreate(i:IUnknown):Boolean;virtual;cdecl; { return TRUE; } // return FALSE to disable create button function HasClassParams():Boolean;virtual;cdecl; {return FALSE;} procedure EditClassParams(hParent:HWND);virtual;cdecl; {} procedure ResetClassParams(fileReset:Boolean=FALSE);virtual;cdecl; {} function NumActionTables():Integer;virtual;cdecl; { return 0; } function GetActionTable(i:Integer):TActionTable;virtual;cdecl; { return NULL; } function IsManipulator():Boolean;virtual;cdecl; { return FALSE; } function CanManipulate(hTarget:TReferenceTarget):Boolean;virtual;cdecl; { return FALSE; } function CanManipulateNode(pNode:INode):Boolean;virtual;cdecl; { return FALSE; } function CreateManipulator(hTarget:TReferenceTarget;pNode:INode):TManipulator;overload;virtual;cdecl; { return NULL; } function CreateManipulator(pNode:INode):TManipulator;overload;virtual;cdecl; {return NULL;} function NeedsToSave():Boolean;virtual;cdecl; { return FALSE; } function Save(isave:ISave):TIOResult;virtual;cdecl; { return IO_OK; } function Load(iload:ILoad):TIOResult;virtual;cdecl; { return IO_OK; } function InitialRollupPageState():DWord;virtual;cdecl; { return 0x7fffffff; } function InternalName():PAnsiChar;virtual;cdecl; { return NULL; } function HInstance():Cardinal;virtual;cdecl; { return NULL; } function NumParamBlockDescs():Integer;virtual;cdecl; { return 0; } function GetParamBlockDesc(i:Integer):TParamBlockDesc2;virtual;cdecl; { return NULL; } function GetParamBlockDescByID(id:BlockID):TParamBlockDesc2;virtual;cdecl; { return NULL; } procedure AddParamBlockDesc(pbd:TParamBlockDesc2);virtual;cdecl; { } procedure BeginEditParams(ip:IObjParam; obj:TReferenceMaker; flags:Longword; prev:TAnimatable);virtual;cdecl; { } procedure EndEditParams(ip:IObjParam; obj:TReferenceMaker; flags:Longword; prev:TAnimatable);virtual;cdecl; { } procedure InvalidateUI(pbd:TParamBlockDesc2);virtual;cdecl; { } {CoreExport} function GetRsrcString(id:INT_PTR):PAnsiChar;virtual;cdecl; procedure MakeAutoParamBlocks(owner:TReferenceMaker);virtual;cdecl; { } function NumParamMaps():Integer;virtual;cdecl; { return 0; } function GetParamMap(i:Integer):IParamMap2;overload;virtual;cdecl; { return NULL; } function GetParamMap(pbd:TParamBlockDesc2):IParamMap2;overload;virtual;cdecl; { return NULL; } procedure SetUserDlgProc(pbd:TParamBlockDesc2; proc:TParamMap2UserDlgProc=nil);virtual;cdecl; { } function GetUserDlgProc(pbd:TParamBlockDesc2):TParamMap2UserDlgProc;virtual;cdecl; { return NULL; } function DrawRepresentation(bkColor:COLORREF; DC:HDC; Rect:TRect):Boolean;virtual;cdecl; { return FALSE; } function NumInterfaces():integer;virtual;cdecl; { return interfaces.Count(); } function GetInterfaceAt(i:Integer):FPInterface;virtual;cdecl; { return interfaces[i]; } {CoreExport} function GetInterface(id:TInterface_ID):FPInterface;overload;virtual;cdecl; {CoreExport} function GetInterface(name:PAnsiChar):FPInterface;overload;virtual;cdecl; {CoreExport} procedure AddInterface(fpi:FPInterface);virtual;cdecl; procedure ClearInterfaces();virtual;cdecl; { interfaces.ZeroCount(); } function SubClassID():TClass_ID;virtual;cdecl; { return Class_ID(); } function Execute(cmd:Integer; arg1:ULONG_PTR=0; arg2:ULONG_PTR=0; arg3:ULONG_PTR=0):INT_PTR;virtual;cdecl; { return 0; } end;
Реализация класса полнотью аналогична сишной выше, но в данном случае никаких дополнительных методов не понадобилось - 3ds все воспринимает и вызывает правильно, как и должно быть согласно MSDN:
destructor ClassDesc.ClassDesc(); begin inherited; end; function ClassDesc.IsPublic():integer;cdecl; // Show this in create branch? begin MessageBox(0,'IsPublic','ClassDesc',MB_OK); Result:=1; end; function ClassDesc.Creat(loading:Boolean=FALSE):Pointer;cdecl; // return a pointer to an instance of the class. begin MessageBox(0,'Creat','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.BeginCreate(i:IUnknown):Integer;cdecl; {return 0;} begin MessageBox(0,'BeginCreate','ClassDesc',MB_OK); Result:=0; end; function ClassDesc.EndCreate(i:IUnknown):Integer;cdecl; {return 0;} begin MessageBox(0,'EndCreate','ClassDesc',MB_OK); Result:=0; end; function ClassDesc.ClassName():PAnsiChar;cdecl; begin MessageBox(0,'ClassName','ClassDesc',MB_OK); Result:=pchClassName; Result:=nil; end; function ClassDesc.SuperClassID():SClass_ID;cdecl; begin MessageBox(0,'SuperClassID','ClassDesc',MB_OK); Result:=UTILITY_CLASS_ID; end; function ClassDesc.ClassID():MClass_ID;cdecl; begin MessageBox(0,'ClassID','ClassDesc',MB_OK); Result:=m_id; end; function ClassDesc.Category():PAnsiChar;cdecl; // primitive/spline/loft/ etc begin MessageBox(0,'Category','ClassDesc',MB_OK); Result:=nil; Result:=pchCategory; end; function ClassDesc.OkToCreate(i:IUnknown):Boolean;cdecl; { return TRUE; } // return FALSE to disable create button begin MessageBox(0,'OKCreate','ClassDesc',MB_OK); Result:=True; end; function ClassDesc.HasClassParams():Boolean;cdecl; {return FALSE;} begin MessageBox(0,'HasClassParams','ClassDesc',MB_OK); Result:=False; end; procedure ClassDesc.EditClassParams(hParent:HWND);cdecl; {} begin MessageBox(0,'EditClassParams','ClassDesc',MB_OK); end; procedure ClassDesc.ResetClassParams(fileReset:Boolean=FALSE);cdecl; {} begin MessageBox(0,'ResetClassParams','ClassDesc',MB_OK); end; function ClassDesc.NumActionTables():Integer;cdecl; { return 0; } begin MessageBox(0,'NewActTable','ClassDesc',MB_OK); Result:=0; end; function ClassDesc.GetActionTable(i:Integer):TActionTable;cdecl; { return NULL; } begin MessageBox(0,'GetActTable','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.IsManipulator():Boolean;cdecl; { return FALSE; } begin MessageBox(0,'IsManip','ClassDesc',MB_OK); Result:=False; end; function ClassDesc.CanManipulate(hTarget:TReferenceTarget):Boolean;cdecl; { return FALSE; } begin MessageBox(0,'CanManipulate','ClassDesc',MB_OK); Result:=False; end; function ClassDesc.CanManipulateNode(pNode:INode):Boolean;cdecl; { return FALSE; } begin MessageBox(0,'CanManipulateNode','ClassDesc',MB_OK); Result:=False; end; function ClassDesc.CreateManipulator(hTarget:TReferenceTarget;pNode:INode):TManipulator;cdecl; { return NULL; } begin MessageBox(0,'CreateManipulator','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.CreateManipulator(pNode:INode):TManipulator;cdecl; {return NULL;} begin MessageBox(0,'CreateManipulator','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.NeedsToSave():Boolean;cdecl; { return FALSE; } begin MessageBox(0,'NeedsToSave','ClassDesc',MB_OK); Result:=False; end; function ClassDesc.Save(isave:ISave):TIOResult;cdecl; { return IO_OK; } begin MessageBox(0,'Save','ClassDesc',MB_OK); result:=IO_OK; end; function ClassDesc.Load(iload:ILoad):TIOResult;cdecl; { return IO_OK; } begin MessageBox(0,'Load','ClassDesc',MB_OK); result:=IO_OK; end; function ClassDesc.InitialRollupPageState():Longword;cdecl; { return 0x7fffffff; } begin MessageBox(0,'InitialRollupPageState','ClassDesc',MB_OK); result:=$7fffffff; end; function ClassDesc.InternalName():PAnsiChar;cdecl; { return NULL; } begin MessageBox(0,'IntName','ClassDesc',MB_OK); Result:=pchClassName; end; function ClassDesc.HInstance():Cardinal;cdecl; { return NULL; } begin MessageBox(0,'hInstance','ClassDesc',MB_OK); Result:=hInstance; end; function ClassDesc.NumParamBlockDescs():Integer;cdecl; { return 0; } begin MessageBox(0,'NumParamBlockDescs','ClassDesc',MB_OK); Result:=0; end; function ClassDesc.GetParamBlockDesc(i:Integer):TParamBlockDesc2;cdecl; { return NULL; } begin MessageBox(0,'GetParamBlockDesc','ClassDesc',MB_OK); result:=nil; end; function ClassDesc.GetParamBlockDescByID(id:BlockID):TParamBlockDesc2;cdecl; { return NULL; } begin MessageBox(0,'GetParamBlockDescByID','ClassDesc',MB_OK); result:=nil; end; procedure ClassDesc.AddParamBlockDesc(pbd:TParamBlockDesc2);cdecl; { } begin MessageBox(0,'AddParamBlockDesc','ClassDesc',MB_OK); end; procedure ClassDesc.BeginEditParams(ip:IObjParam; obj:TReferenceMaker; flags:Longword; prev:TAnimatable);cdecl; { } begin MessageBox(0,'BeginEditParams','ClassDesc',MB_OK); end; procedure ClassDesc.EndEditParams(ip:IObjParam; obj:TReferenceMaker; flags:Longword; prev:TAnimatable);cdecl; { } begin MessageBox(0,'EndEditParams','ClassDesc',MB_OK); end; procedure ClassDesc.InvalidateUI(pbd:TParamBlockDesc2);cdecl; { } begin MessageBox(0,'InvalidateUI','ClassDesc',MB_OK); end; function ClassDesc.GetRsrcString(id:INT_PTR):PAnsiChar;cdecl; begin MessageBox(0,'GetRsrcStr','ClassDesc',MB_OK); Result:=nil; end; procedure ClassDesc.MakeAutoParamBlocks(owner:TReferenceMaker);cdecl; { } begin MessageBox(0,'MakeAutoParamBlocks','ClassDesc',MB_OK); end; function ClassDesc.NumParamMaps():Integer;cdecl; { return 0; } begin MessageBox(0,'NumParamMaps','ClassDesc',MB_OK); Result:=0; end; function ClassDesc.GetParamMap(i:Integer):IParamMap2;cdecl; { return NULL; } begin MessageBox(0,'GetParamMap','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.GetParamMap(pbd:TParamBlockDesc2):IParamMap2;cdecl; { return NULL; } begin MessageBox(0,'GetParamMap1','ClassDesc',MB_OK); Result:=nil; end; procedure ClassDesc.SetUserDlgProc(pbd:TParamBlockDesc2; proc:TParamMap2UserDlgProc=nil);cdecl; { } begin MessageBox(0,'SetupDlgProc','ClassDesc',MB_OK); end; function ClassDesc.GetUserDlgProc(pbd:TParamBlockDesc2):TParamMap2UserDlgProc;cdecl; { return NULL; } begin MessageBox(0,'GetUserDlgProc','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.DrawRepresentation(bkColor:COLORREF; DC:HDC; Rect:TRect):Boolean;cdecl; { return FALSE; } begin MessageBox(0,'DrawRepr','ClassDesc',MB_OK); Result:=False; end; function ClassDesc.NumInterfaces():integer;cdecl; { return interfaces.Count(); } begin MessageBox(0,'NumInterfaces','ClassDesc',MB_OK); Result:=0; end; function ClassDesc.GetInterfaceAt(i:Integer):FPInterface;cdecl; { return interfaces[i]; } begin MessageBox(0,'GetInterfaceAt','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.GetInterface(id:TInterface_ID):FPInterface;cdecl; begin MessageBox(0,'GetInterface','ClassDesc',MB_OK); Result:=nil; end; function ClassDesc.GetInterface(name:PAnsiChar):FPInterface;cdecl; begin MessageBox(0,'GetInterface1','ClassDesc',MB_OK); Result:=nil; end; procedure ClassDesc.AddInterface(fpi:FPInterface);cdecl; begin MessageBox(0,'AddInterface','ClassDesc',MB_OK); end; procedure ClassDesc.ClearInterfaces();cdecl; { interfaces.ZeroCount(); } begin MessageBox(0,'ClearInterface','ClassDesc',MB_OK); end; function ClassDesc.SubClassID():TClass_ID;cdecl; { return Class_ID(); } begin MessageBox(0,'SubClassId','ClassDesc',MB_OK); Result:=c_id;//self.ClassID(); end; function ClassDesc.Execute(cmd:Integer; arg1:ULONG_PTR=0; arg2:ULONG_PTR=0; arg3:ULONG_PTR=0):INT_PTR;cdecl; { return 0; } begin MessageBox(0,'Execute','ClassDesc',MB_OK); Result:=0; end;
Последовательность вызовов прежняя, все работает вплоть до вызова InitialRollupState. На этом методе 3ds вылетает. Почему? Где ошибка, что не так? Может с PChar`ами что ему не нравится?
Если проблема решится, половина дела будет сделана.
InitialRollupPageState ты хотел сказать? Може MessageBox мешает?
Тема в архиве.