Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2009.10.18;
Скачать: [xml.tar.bz2];

Вниз

В продолжение темы про DLL-классы на Delphi и MSVC. Нужен совет!   Найти похожие ветки 

 
ПЗ   (2008-08-06 21:23) [0]

Имею плагин для 3d Studio MAX, написанный на С. Хочу написать его на Delphi. Плагин сидит в DLL, экспортирующей функцию, которая возвращает указатель на следующий класс (MessageBox вставлены мною для отладки):

// класс-описатель для вашего plug-in"а
class MyUtilityClassDesc
{
private:
 Tab<FPInterface*>  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м. далее). Есть проблема, тебуется опытный глаз!


 
ПЗ   (2008-08-06 21:25) [1]


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 для контроля правильности вызовов методов. Здесь все вызывается правильно и никаких левых методов-пустышек не требуется (см. ниже).


 
ПЗ   (2008-08-06 21:28) [2]

//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:58) [3]

С чего бы везде cdecl понатыкано ?
Не понятно ..
И вообще - есть же, наверно, документация по API для плагинов к этому продукту, почему бы ее не проштудировать, прежде чем лепить невесть что ?


 
tesseract ©   (2008-08-06 22:32) [4]

Классы в DLL.... ИМХО там Com-server.


 
ПЗ   (2008-08-07 21:05) [5]

Нет, там не COM-сервер, а к сожалению, именно классы в DLL :-( Документация есть, но не на API, а на эти самые классы. И заголовочники есть на С++. Ровно по ним все и делалось. Отсюда и cdecl везде – все методы должны иметь сишные правила вызова. Я извиняюсь за большой объем кода выше, там 90% методов для мебели сделаны. Значение имеют только то, что не в строчку записаны :-) ClassName, Category, ClassID, SuperClassID, InitialPageRollupState.

Имею следующее подозрение: Метод ClassDesc::ClassID() согласно документации и сишному заголовочнику, возвращает непосредственно экземпляр класса Class_ID. Не указатель на него, а по значению. Вопрос: а на делфи тот же метод будет у меня возвращать объект моего аналога данного класса TClass_ID по значению?
Сюда же – согласно документации, сам класс ClassDesc не имеет конструктора! Деструктор (виртуальный) есть, а конструктора нет. На делфи он есть по-умолчанию (от TObject). Это может сыграть?


 
Сергей М. ©   (2008-08-08 08:13) [6]


> на делфи тот же метод будет у меня возвращать объект моего
> аналога данного класса TClass_ID по значению?


Как бы ни осуществлялся возврат (а осуществляется он в делфи всегда по ссылке), дельфийские классы никаким боком не пересекаются с сишными.


 
oxffff ©   (2008-08-08 12:12) [7]


>
> Все бы хорошо, но после вызова InitialPageRollupState происходит
> крэш! Как мне найти ошибку? Не наврал ли я с возвращением
> Pchar`ов и ClaccID()? Сам класс TClassID - простейший -
> два поля и несколько методов для доступа к ним. Если надо
> - приведу отдельно. Help!


О, я как раз из отпуска приехал.
Вроде же разобрали как делать месяц назад.
Не мог бы ты сократить код до минимума с сохранением ошибки?


 
ПЗ   (2008-08-08 20:13) [8]

ОК, попробую.  Что в прошлый раз обсудили, работает. В чем сейчас проблема – ХЗ:
Итак, имеем: class MyUtilityClassDesc
{
public:
virtual void AAA() {}// – ХЗ №1
virtual void BBB() {}// – ХЗ №2
virtual ~MyUtilityClassDesc() { }//Деструктор. Конструктора нет!
virtual int IsPublic() {  return 1; }

virtual const TCHAR *  ClassName() {   return _T("MyUtility");  }
virtual SClass_ID SuperClassID() {  return 0x1020;  }
virtual CClassID ClassID() {   return CClass_ID(); }
virtual const TCHAR * Category() {   return _T("Utility"); }

virtual int NumActionTables() { return 0; }

virtual DWORD   InitialRollupPageState()  {    return 0x7fffffff; }

};

MyUtilityClassDesc.ClassID() возвращает экземпляр следующего класса:

class CClassID
{
private:
 ULONG a,b;
 public:
   CClassID() { a = b = 0xffffffff; }
   CClassID(const CClassID& cid) { a = cid.a; b = cid.b;  }
   CClassID(ulong aa, ulong bb) { a = aa; b = bb; }
   ULONG PartA() const { return a; }
   ULONG PartB() const { return b; }
   void SetPartA( ulong aa ) { a = aa; }    
   void SetPartB( ulong bb ) { b = bb; }
   int operator==(const CClassID& cid)  { return (a==cid.a&&b==cid.b);}
   int operator!=(const CClassID& cid) const { return (a!=cid.a||b!=cid.b); }
   CClassID& operator=(const CClassID& cid)  { a=cid.a; b = cid.b; return (*this); }
   bool operator<(const CClassID& rhs) const  { return false;  }
 };

В этом виде все ОК. Последовательность вызова методов выше написал. Из CClassID вызывается только конструктор.
Delphi-аналоги:

ClassDesc=class {MaxHeapOperators}
 public
   destructor          ClassDesc();virtual;
   function IsPublic():integer;virtual;cdecl;  
   …
   function ClassName():PAnsiChar;virtual;cdecl;
   function SuperClassID():SClass_ID;virtual;cdecl;
   function ClassID():TClass_ID;virtual;cdecl;
   function Category():PAnsiChar;virtual;cdecl;  

   function NumActionTables():Integer;virtual;cdecl;

   function InitialRollupPageState():DWord;virtual;cdecl;
   function InternalName():PAnsiChar;virtual;cdecl;

end;
destructor ClassDesc.ClassDesc();
begin
 inherited;
end;
function ClassDesc.IsPublic():integer;cdecl;  
begin
 Result:=1;
end;
function ClassDesc.ClassName():PAnsiChar;cdecl;
begin
 Result:=pchClassName; //const pchClassName:PAnsiChar=’Delphi’;
end;
function ClassDesc.SuperClassID():SClass_ID;cdecl;
begin
 Result:=$1020;;
end;
function ClassDesc.ClassID():TClass_ID;cdecl;
begin
 Result:=c_id; //var c_id:TClass_ID; c_id:=TClass_ID.Create($11,$12);
end;
function ClassDesc.Category():PAnsiChar;cdecl;   etc
begin
 Result:=pchCategory; //const pchCategory:PAnsiChar=’Utility’;
end;
function ClassDesc.NumActionTables():Integer;cdecl;
begin
 Result:=0;
end;
function ClassDesc.InitialRollupPageState():Longword;cdecl;
begin
 result:=$7fffffff;
end;

Аналог класса CClass_ID:

TClass_ID=class {MaxHeapOperators}
 a,b:Longword;
 public
   constructor Class_ID();overload;    
   constructor Class_ID(var cid:TClass_ID);overload;    
   constructor Class_ID(aa:Longword; bb:Longword);overload;    
   function PartA():Longword;
   function PartB():Longword;
   procedure SetPartA(aa:Longword);
   procedure SetPartB(bb:Longword);
   function operatorEq(var cid:TClass_ID):integer;
   function operatorNEq(var cid:TClass_ID):integer;
   function operatorAssign(var cid:TClass_ID):TClass_ID;
   function operatorLess(var cid:TClass_ID):Boolean;
end;

constructor TClass_ID.Class_ID();
begin
  a:=$ffffffff;
  b:=a;
end;

constructor TClass_ID.Class_ID(var cid:TClass_ID);
begin
 a:=cid.a;
 b:=cid.b;
end;
constructor TClass_ID.Class_ID(aa:Longword; bb:Longword);
begin
 a:=aa;
 b:=bb;
end;
function TClass_ID.PartA():Longword;
begin
Result:=a;
end;
function TClass_ID.PartB():Longword;
begin
Result:=b;
end;
procedure TClass_ID.SetPartA(aa:Longword);
begin
 a:=aa;
end;
procedure TClass_ID.SetPartB(bb:Longword);
begin
 b:=bb;
end;
function TClass_ID.operatorEq(var cid:TClass_ID):integer; begin
 Result:=0;
 if (a=cid.a)and(b=cid.b)then Result:=1;
end;
function TClass_ID.operatorNEq(var cid:TClass_ID):integer; begin
 Result:=0;
 if (a<>cid.a)or(b<>cid.b)then Result:=1;
end;
function TClass_ID.operatorAssign(var cid:TClass_ID):TClass_ID; begin
 a:=cid.a;
 b:=cid.b;
 Result:=self;
end;
function TClass_ID.operatorLess(var cid:TClass_ID):Boolean;
begin
  Result:=false;
  if (a<cid.a)or((a=cid.a)and(b<cid.b))then Result:=True;
end;

В данном случае, последовательность вызовов сохраняется, все ОК, но после InitialPageRollupState имею Access Violation.

ЗЫ. Строго говоря, в SDK оба класса наследуются от единого предка, которые не имеет виртуальных методов, а содержит несколько вариантов невиртуальных операторов new и delete. Однако, в сишном примере, все и без них работает. Почему не работает на Delphi?


 
oxffff ©   (2008-08-09 14:54) [9]


> ПЗ   (08.08.08 20:13) [8]


При очень беглом обзоре на [8]
(в понедельник на работе я постараюсь посмотреть более внимательно).
Я нашел следующее несоответствие.

ClassDesc=class {MaxHeapOperators}
public
  destructor          ClassDesc();virtual;
...

destructor ClassDesc.ClassDesc();
begin
inherited;          <-этот вызов может приводить к AV.
end;

Поскольку в Delphi указатель на VMT по отрицательным смещениям имеет виртуальные методы. В том числе и на начальный деструктор.
В С++ этот виртуальный деструктор будет расположен по положительным смешениям. В этом будет не соответствие.


 
oxffff ©   (2008-08-09 14:57) [10]


> oxffff ©   (09.08.08 14:54) [9]


Может приводить поскольку я не знаю по твоему коду описание декструктора MaxHeapOperators.
Если он перекрывает стандартный декструктор, то проблемы гарантированы на 100%. Если вызов стандартного перекрытого не используется, тогда проблем быть не должно.


 
ПЗ   (2008-08-09 20:18) [11]

Нет, точно не здесь. Деструктор вызывается (я контролировал) после закрытия 3ds, когда все библиотеки выгружаются. А у меня они и загрузиться не успевают :-)))
На всякий случай, вот код этого самого MaxHeapOperators:

#ifdef BLD_UTIL
#define UtilExport __declspec( dllexport )
#else
#define UtilExport __declspec( dllimport )
#endif

class MaxHeapOperators
{
public:
UtilExport static void* operator new( size_t size );
UtilExport static void* operator new( size_t size, const std::nothrow_t & e );
UtilExport static void* operator new( size_t size, const char* filename, int line );
UtilExport static void* operator new( size_t size, const std::nothrow_t & e, const char * filename, int line );
UtilExport static void* operator new( size_t size, unsigned long flags );
UtilExport static void* operator new( size_t size, const std::nothrow_t & e, unsigned long flags );
UtilExport static void* operator new[]( size_t size );
UtilExport static void* operator new[]( size_t size, const std::nothrow_t & e );
UtilExport static void* operator new[]( size_t size, const char* filename, int line );
UtilExport static void* operator new[]( size_t size, const std::nothrow_t & e, const char * filename, int line );
UtilExport static void* operator new[]( size_t size, unsigned long flags );
UtilExport static void* operator new[]( size_t size, const std::nothrow_t & e, unsigned long flags );

UtilExport static void operator delete( void * ptr );
UtilExport static void operator delete( void * ptr, const std::nothrow_t& e );
UtilExport static void operator delete( void * ptr, const char * filename, int line );
UtilExport static void operator delete( void * ptr, const std::nothrow_t & e, const char * filename, int line );
UtilExport static void operator delete( void * ptr, unsigned long flags );
UtilExport static void operator delete( void * ptr, const std::nothrow_t & e, unsigned long flags );
UtilExport static void operator delete[]( void * ptr );
UtilExport static void operator delete[]( void * ptr, const std::nothrow_t& e );
UtilExport static void operator delete[]( void * ptr, const char * filename, int line );
UtilExport static void operator delete[]( void * ptr, const std::nothrow_t& e, const char * filename, int line );
UtilExport static void operator delete[]( void * ptr, unsigned long flags );
UtilExport static void operator delete[]( void * ptr, const std::nothrow_t&e, unsigned long flags );
UtilExport static void* operator new( size_t size, void * placement_ptr );
UtilExport static void  operator delete( void * ptr, void * placement_ptr );
};

Реализацию опускаю за тривиальностью. Есть подозрение, что неизвестные методы AAA() и BBB(), которые мне пришлось добавить в сишной реализации - это конструктор по-умолчанию и конструктор копий. Где-то в MSDN попадалось, что они должны автоматически добавляться к любому классу. Тем более, что BBB() на этапе загрузки ВЫЗЫВАЕТСЯ. Я только сегодня это обнаружил, вставив MessageBox.


 
ПЗ   (2008-08-11 21:00) [12]

Сегодня попробовал отладчиком смотреть, но адреса AV все время разные :-(


 
oxffff ©   (2008-08-14 08:51) [13]

Почему у тебя не совпадают позиции соответствующих методов в виртуальных таблицах?

Итак, имеем: class MyUtilityClassDesc
{
public:
virtual void AAA() {}// – ХЗ №1
virtual void BBB() {}// – ХЗ №2
virtual ~MyUtilityClassDesc() { }//Деструктор. Конструктора нет!
virtual int IsPublic() {  return 1; }

ClassDesc=class {MaxHeapOperators}
public
  destructor          ClassDesc();virtual;            
  function IsPublic():integer;virtual;cdecl;  
  …
  function ClassName():PAnsiChar;virtual;cdecl;
  function SuperClassID():SClass_ID;virtual;cdecl;
  function ClassID():TClass_ID;virtual;cdecl;
  function Category():PAnsiChar;virtual;cdecl;  

То есть при вызове ClassDesc.IsPublic(Delphi) у тебя будет вызываться
MyUtilityClassDesc.BBB(C++)


 
ПЗ   (2008-08-14 21:11) [14]

Я выше написал - методы AAA, BBB пришлось добавлять только на C-реализации. На Delphi они не нужны (последовательность вызовов тогда нарушается). На delphi первым (как и должно быть) вызывается ClassDesc.SuperClassID, потом ClassDesc.ClassID, ClassDesc.SuperClassID, ClassDesc.IsPublic, ClassDesc.ClassID, ClassDesc.Category, ClassDesc.InitialRollupState. После этого происходит крэш.

Аналогичная последовательность (я проверил) у настоящих фирменных плагинов, написанных на C++ с наследованием от заголовочников и LIB из SDK.

Когда я попробовал написать MyUtilityClassDesc (выше) на С++ БЕЗ LIB из SDK (скопировал класс из заголовочника), у  меня первым вызвался не SuperClassID, а Category(), который на две позиции ниже в VMT (что вызывало крэш, ессно). Экспериментальным путем я добавил два виртуальных метода и все заработало.

Сейчас проверил еще раз сишный вариант. BBB() вызывается перед IsPublic. ААА() не вызывается. ХЗ что это такое? М.б. конструктор копий там должен был быть? В заголовочнике SDK его нет.


 
ПЗ   (2008-08-14 21:19) [15]

На всякий случай, попробую еще внести ясность. Итак имею:
1. "Совсем честную" DLL на С++ с использованием *.LIB и *.Н из SDK:
class MyUtilityClassDesc:public ClassDesc
где
class ClassDesc: public MaxHeapOperators - оба сидят в SDK.
Это честный павильный плагин, который работает. Методы вызывыются в последовательности, описанной выше.

2. "Не совсем честную" DLL на С++ без использования *.LIB и *.Н из SDK:
class MyUtilityClassDesc - сидит в самой DLL, ни от чего не наследуется.
Все работает, при условии добавления ААА,ВВВ. Последовательность вызовов как в п.1.

3."Совсем не честную" DLL на Delphi без использования *.LIB и *.Н из SDK:
ClassDesc=class ... end;  - сидит в самой DLL, ни от чего не наследуется.
Никаких доп. методов не требуется. Последовательность вызовов совпадает с п.1, но после InitialPageRollupState крэш :-(
Уф....


 
oxffff ©   (2008-08-14 22:44) [16]


> М.б. конструктор копий там должен был быть?


Обычный конструктор и конструктор копий в С++ не может быть виртуальным. Рекомендую посмотреть под отладчиком сами вызовы в честных и не честных случаях и тогда все станет кристально понятно.


 
ПЗ   (2008-08-15 21:02) [17]

А что понимается под "посмотреть под отладчиком сами вызовы"? Исходников SDK у меня нет, только заголовочники. Брейкпоинты в методы я вставлял, но это то же, что и MessageBox. Что еще можно посмотреть?


 
oxffff ©   (2008-08-15 21:32) [18]


> ПЗ   (15.08.08 21:02) [17]


Посмотри внимательно, как происходит вызов метода и как и куда кладутся параметры на ассемблере в 1,2,3 из [15].
1. Посмотри как происходит сам вызов через таблицу VMT(какие смещения используются), сравни и найди разницу.
2. Корректно ли передаются параметры. И то ли ты передаешь в случае с Delphi.

Соответственно так ты сможешь найти причину.
Поскольку меня смущает твоя фраза


....

> Все работает, при условии добавления ААА,ВВВ. Последовательность
> вызовов как в п.1.
....
>... Delphi
> Никаких доп. методов не требуется.


По твоему получается, что VMT смещения в Delphi начинаются с нуля.
А на примере 2 для С++ начинаюся с "+8". Так быть не может.


 
ПЗ   (2008-08-16 20:22) [19]

ОК, буду пробовать. В ассемблере я совсем не варю. В классе TObject я насчитал как минимум 8 виртуальных методов. Все они, как я понимаю, автоматом переползают в мой ClassDesc из-за наследования.


 
ПЗ   (2008-08-18 20:48) [20]

Вопрос по отладчику: как посмотреть вызов метода, если его вызывает чужая программа?
Я поставил брейкпоинт на нужный метод, и ессно, вижу внутренности этого метода, когда прога останавливается на брейкпоинте. А как мне посмотреть сам момент его вызова?


 
oxffff ©   (2008-08-18 21:09) [21]

Поставить бряк при выходе из процедуры на вызове.


 
ПЗ   (2008-08-19 21:01) [22]

Эээ... Так при выходе или на вызове? Если второе, то как это сделать? Вызов из другой программы идет. У меня исходников 3ds нет.

На выходе я ставил, но после ret содержимое регистров меняется. Чистоты эксперимента нет.


 
oxffff ©   (2008-08-19 21:33) [23]


> ПЗ   (19.08.08 21:01) [22]


Выходишь(из процедуры) по ret и мотаешь вверх(назад) до вызова процедуры. Ставишь бряк там. Смотришь передачу параметров и сам вызов.
Соблюдая терпение(если их будет несколько), попадаешь в свою процедуру.


 
ПЗ   (2008-08-25 21:27) [24]

Жесть... Похоже один из методов врет с передачей параметров (которых нет) или с соглашением о вызове. Где-то неверно очищается стек. Идет CALL, но перед RET корректный адрес возврата в стее оказываетеся на одну позицию выше, чем надо. В результате - возврат в пустоту...



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2009.10.18;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.59 MB
Время: 0.009 c
15-1250623324
{RASkov}
2009-08-18 23:22
2009.10.18
Песня про арбуз


3-1228230921
mosco
2008-12-02 18:15
2009.10.18
Uniqueidentifier в фигурных скобках, как от них избавиться?


11-1175699064
!Pharaon!
2007-04-04 19:04
2009.10.18
Пару вопросов по KOL


2-1250064945
belmol
2009-08-12 12:15
2009.10.18
Найти сумму степенного ряда


3-1227770209
alexnmsk
2008-11-27 10:16
2009.10.18
Microsoft SQL Server и RAISERROR





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский