![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
В продолжение темы про DLL-классы на Delphi и MSVC. Нужен совет!
ПЗ © (2008-08-06 21:23:00)Имею плагин для 3d Studio MAX, написанный на С. Хочу написать его на Delphi. Плагин сидит в DLL, экспортирующей функцию, которая возвращает указатель на следующий класс (MessageBox вставлены мною для отладки):
// класс-описатель для вашего plug-in'а
class MyUtilityClassDesc
{
private:
Tab interfaces; // the FnPub interfaces published by this plugin
// maxutil.lib needed!
public:
virtual void AAA() {}
virtual void BBB() {}
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; }
};
Два виртуальных метода вначале - пустышки. Зачем нужны - ХЗ, но без них последовательность вызовов методов нарушается. Последовательность следующая:
1. MyUtilityClassDesc.SuperClassID()
2. MyUtilityClassDesc.ClassID()
3. MyUtilityClassDesc.SuperClassID()
4. MyUtilityClassDesc.IsPublic()
5. MyUtilityClassDesc.ClassID()
6. MyUtilityClassDesc.ClassName()
7. MyUtilityClassDesc.Category()
8. MyUtilityClassDesc.InitialPageRollupState()
9. MyUtilityClassDesc.NemActionTables()
....
Написал аналог на Delphi (cм. далее). Есть проблема, тебуется опытный глаз!
tesseract (2008-08-06 22:32:00) [21]Классы в DLL.... ИМХО там Com-server.
Сергей М. (2008-08-06 21:58:00) [22]С чего бы везде cdecl понатыкано ?
Не понятно ..
И вообще - есть же, наверно, документация по API для плагинов к этому продукту, почему бы ее не проштудировать, прежде чем лепить невесть что ?
ПЗ (2008-08-06 21:28:00) [23]//ClassDesc
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():TClass_ID;cdecl;
begin
MessageBox(0,'ClassID','ClassDesc',MB_OK);
Result:=c_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;c decl; { 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.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;
Все бы хорошо, но после вызова InitialPageRollupState происходит крэш! Как мне найти ошибку? Не наврал ли я с возвращением Pchar`ов и ClaccID()? Сам класс TClassID - простейший - два поля и несколько методов для доступа к ним. Если надо - приведу отдельно. Help!
ПЗ (2008-08-06 21:25:00) [24]
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():TClass_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;vi rtual;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;
Реализацию сделал аналогично сишному аналогу, и тоже вставил MessageBox для контроля правильности вызовов методов. Здесь все вызывается правильно и никаких левых методов-пустышек не требуется (см. ниже).