Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi's Interfaces in C++ (https://www.delphipraxis.net/134910-delphis-interfaces-c.html)

Desmulator 1. Jun 2009 08:45


Delphi's Interfaces in C++
 
Gute Morgen alle zusammen,

angesichts der Tatsache, das ich eine geschrieben DLL testen muss, habe ich einen Punkt erreicht indem ich mit meinen nahezu nichtigen C++ Kenntnissen nicht mehr weiter komme. Also ich habe meine selbst geschriebene DLL bereits mit mehrern Delphiversionen und auch Lazarus, FreePascal, getestet. Alles läuft wunder bar. Daher habe ich mit dran gesetzt und wollte die header nach C++ überführen. Klappte auch ganz gut, zumindest bei den records bzw. structs und den enums. Bei "set's" habe ich einfe Konstanten benutzt ( wie manns kennt 1, 2, 4, 8, ... ). So dann kamen die Funktione. :? Da gab es ja schon etwas mehr aufwand, allerdings konnte ich nach langem suchen ein DLL2Lib Programm finden, wodurch das alles wieder recht einfach wurde. Alles super, Daumen hoch. Doch dann, dann kamen die COM-Interfaces. :freak:

Ich benutze für C++ das FreeWare Programm Dev-C++, welches mir von einem Kumpel empfohlen wurde. Nun habe ich mir die DirectX-Headers mal angegukt und nachgesehen wie dort die Interfaces beschrieben wurden. Ich übernahm den Aufbau und passte ihn an mein Interface an. Doch dann wurde ich vom Compiler bestraft, es fehle eine vtable für das Interface.

Wo bzw. Wie bekomme ich die vtable?
Muss ich Interfaces etwa auch auf die Exportliste stellen?
Gibt es gute Tools für D2C?

Mfg Desmu

Apollonius 1. Jun 2009 09:26

Re: Delphi's Interfaces in C++
 
Eigentlich sollte ein Interface in C++ eine Klasse ohne Felder sein, deren Methoden alle abstrakt (pure virtual) sind. Außerdem sollte die Klasse von IUnknown abgeleitet sein. Kannst du mal zeigen, wie es zur Zeit aussieht?

Desmulator 1. Jun 2009 10:04

Re: Delphi's Interfaces in C++
 
DelphiUnit
Delphi-Quellcode:
unit BaseEngine;

interface

type
  TBaseResult = Cardinal;
  TBaseHandle = Cardinal;

  TBaseDateMonth = 1..12;
  TBaseDateDay = 1..31;
  TBaseTimeHour = 0..23;
  TBaseTimeMinute = 0..59;
  TBaseTimeSecond = 0..59;

  TBaseDateTime = record
    Year : Word;
    Month: TBaseDateMonth;
    Day : TBaseDateDay;
    Hour : TBaseTimeHour;
    Minute : TBaseTimeMinute;
    Second : TBaseTimeSecond;
  end;

  TBaseDate = record
    Year : Word;
    Month: TBaseDateMonth;
    Day : TBaseDateDay;
  end;

  TBaseTime = record
    Hour : TBaseTimeHour;
    Minute : TBaseTimeMinute;
    Second : TBaseTimeSecond;
  end;

  TBaseFileAttribute = ( bfaArchive, bfaDirectory, bfaHidden, bfaReadOnly, bfaSystem, bfaTemporary, bfaCompressed, bfaOffline, bfaNotContentIndexed, bfaEncrypted );
  TBaseFileAttributes = record
    Archive          : Boolean;
    Hidden           : Boolean;
    Readonly         : Boolean;
    System           : Boolean;
    Temporary        : Boolean;
    Offline          : Boolean;
    NotContentIndexed : Boolean;
    { Not changeable }
    Directory        : Boolean;
    Compressed       : Boolean;
    Encrypted        : Boolean;
  end;

  TBaseFileOpenMethod = ( bfomClear, bfomOpen, bfomOpenExisting );
  TBaseFileAccess = set of ( bfaRead, bfaWrite );
  TBaseFileShare = set of ( bfsRead, bfsWrite, bsfDelete );

type
  IBaseInterface = interface(IInterface)
    function GetHandle : Pointer; stdcall;
  end;

  IBaseStream = interface(IBaseInterface)
    function GetSize : Cardinal;                  stdcall;
    function GetPosition : Cardinal;              stdcall;
    function SetPosition(NewPosition : Cardinal) : Boolean; stdcall;
    function Seek(By : Integer) : Boolean;                  stdcall;

    function Read(var Buffer; Len : Cardinal) : Boolean; stdcall;
    function Write(var Buffer; Len : Cardinal): Boolean; stdcall;

    function Assign(Stream : IBaseStream) : Boolean; stdcall;
    function WriteTo(Stream : IBaseStream) : Boolean; stdcall;
  end;

  IBaseIOStream = interface(IBaseStream)
  end;

  IBaseFileInfo = interface;

  IBaseFile = interface(IBaseIOStream)
    function GetFileInfo(Extended : Boolean) : IBaseFileInfo; stdcall;
  end;

  IBaseFileInfo = interface(IBaseInterface)
    function GetFullPath   : PChar; stdcall;
    function GetRelativPath : PChar; stdcall;

    function ExtendInformation : Boolean; stdcall;
    function ReduceInformation : Boolean; stdcall;

    function GetAttributes : TBaseFileAttributes; stdcall;
    function GetAttribute(Attribute : TBaseFileAttribute) : Boolean; stdcall;
    function SetAttributes(AttributeBlock : TBaseFileAttributes) : Boolean; stdcall;
    function SetAttribute(Attribute : TBaseFileAttribute; Value : Boolean) : Boolean; stdcall;

    function GetCreateTime : TBaseDateTime; stdcall;
    function GetLastAccessTime : TBaseDateTime; stdcall;
    function GetLastWriteTime : TBaseDateTime; stdcall;
  end;

const
  BASE_INVALID_HANDLE : TBaseHandle = $FFFFFFFF;
  BaseEngineDll = 'BaseEngine.dll';

function BaseVersion : PChar; stdcall; external BaseEngineDll;
function BaseRevision : PChar; stdcall; external BaseEngineDll;
function BaseCompiled : PChar; stdcall; external BaseEngineDll;
function BaseGetErrorStr(Value : TBaseResult) : PChar; stdcall; external 'BaseEngine.dll';
function BaseGetLastErrorStr(Error : PCardinal) : PChar; stdcall; external 'BaseEngine.dll';
function BaseGetLastError : TBaseResult; stdcall; external 'BaseEngine.dll';
function BaseCloseHandle(Handle : TBaseHandle) : Boolean; stdcall; external 'BaseEngine.dll';
function BaseTimeTickCreate : TBaseHandle; stdcall; external 'BaseEngine.dll';
function BaseTimeTickGap(Handle : TBaseHandle) : Cardinal; stdcall; external 'BaseEngine.dll';
function BaseTimeTick(Handle : TBaseHandle) : Cardinal; stdcall; external 'BaseEngine.dll';
function BaseTimeTickPerSec(Handle : TBaseHandle) : Cardinal; stdcall; external 'BaseEngine.dll';
function BaseTimeTickReset(Handle : TBaseHandle) : Boolean; stdcall; external 'BaseEngine.dll';
function BaseCreateFile(FileName : PChar; OpenMethod : TBaseFileOpenMethod; Access : TBaseFileAccess; ShareMode : TBaseFileShare) : IBaseFile; stdcall; external 'BaseEngine.dll';

implementation

end.
C++ Equivalent
Code:
#include <windows.h>

typedef HRESULT TBaseResult;
typedef UINT TBaseHandle;


// Date & Time Records
typedef struct BaseDateTime {
    WORD Year;
    BYTE Month;
    BYTE Day;
    BYTE Hour;
    BYTE Minute;
    BYTE Second;
} TBaseDateTime;

typedef struct BaseDate {
    WORD Year;
    BYTE Month;
    BYTE Day;
} TBaseDate;

typedef struct BaseTime {
    BYTE Hour;
    BYTE Minute;
    BYTE Second;
} TBaseTime;


// FileAttributes and so on
typedef enum {
    bfaArchive,
    bfaDirectory,
    bfaHidden,
    bfaReadOnly,
    bfaSystem,
    bfaTemporary,
    bfaCompressed,
    bfaOffline,
    bfaNotContentIndexed,
    bfaEncrypted
} TBaseFileAttribute;

typedef struct BaseFileAttributes {
    bool Archive;
    bool Hidden;
    bool Readonly;
    bool System;
    bool Temporary;
    bool Offline;
    bool NotContentIndexed;
    bool Directory;
    bool Compressed;
    bool Encrypted;
} TBaseFileAttributes;

// FileEnums, like share options
typedef enum {
    bfomClear,
    bfomOpen,
    bfomOpenExisting  
} TBaseFileOpenMethod;

// Pascals "set of" is not avaible
#define bfaRead UINT(1)
#define bfaWrite UINT(2)

#define bfsRead UINT(1)
#define bfsWrite UINT(2)
#define bfsDelete UINT(4)

/*interface DECLSPEC_UUID("D4C2BA04-9C15-4631-8774-5AE2E05EBB80") IBaseInterface;
typedef interface IBaseInterface;

#undef INTERFACE
#define INTERFACE IBaseInterface
DECLARE_INTERFACE_(IBaseInterface, IUnknown)
{
    __stdcall void* GetHandle;
    STDMETHOD(QueryInterface)(THIS_ REFIID riid, void** ppvObj);
    STDMETHOD_(ULONG,AddRef)(THIS);
    STDMETHOD_(ULONG,Release)(THIS);
};
typedef struct IBaseInterface;*/ // Entfernt, weil fehlerhaft. vTable nicht gefunden


extern "C" {
     __declspec(dllimport) char* BaseVersion(); // Weitere Funktionen aus "kB"-Gründen erstmal noch nicht eingebaut.
}

Apollonius 1. Jun 2009 10:13

Re: Delphi's Interfaces in C++
 
Wo kommen diese Makros DECLARE_INTERFACE_ und STDMETHOD her?

Desmulator 1. Jun 2009 10:22

Re: Delphi's Interfaces in C++
 
Code:
# define STDMETHODCALLTYPE   __stdcall
#  define STDMETHOD(m)   virtual HRESULT STDMETHODCALLTYPE m
..
#  if defined(__GNUC__) && __GNUC__ < 3 && !defined(NOCOMATTRIBUTE)
#   define DECLARE_INTERFACE(i) interface __attribute__((com_interface)) i
#   define DECLARE_INTERFACE_(i,b) interface __attribute__((com_interface)) i : public b
#  else
#   define DECLARE_INTERFACE(i) interface i
#   define DECLARE_INTERFACE_(i,b) interface i : public b
#  endif
Das erhalte ich zumindest, wenn ich mit gedrückter Strg-Taste drauf klicke.

Apollonius 1. Jun 2009 10:33

Re: Delphi's Interfaces in C++
 
Ich wusste gar nicht, dass C das Schlüsselwort Interface kennt. Ich hätte das Interface spontan so übersetzt:
Code:
class IBaseInterface: public IUnknown
{
    virtual __stdcall void* GetHandle() = 0;
}
Meine C++-Kenntnisse sind allerdings sehr beschränkt. Kannst du das so mal ausprobieren?

Desmulator 1. Jun 2009 11:04

Re: Delphi's Interfaces in C++
 
Okay.

Code:
class IBaseInterface: public IUnknown
{
    virtual __stdcall void* GetHandle() = 0;
};

extern "C" {
    ...
    IBaseInterface BaseCreateFileInfo(char* FileName, bool Extended);
}
Zitat:

Compiler: Default compiler
Building Makefile: "C:\Dokumente und Einstellungen\Lars\Desktop\BaseCTest\Makefile.win"
Führt make... aus
make.exe -f "C:\Dokumente und Einstellungen\Lars\Desktop\BaseCTest\Makefile.win" all
g++.exe -D__DEBUG__ -c main.cpp -o main.o -I"C:/Programme/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Programme/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Programme/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Programme/Dev-Cpp/include/c++/3.4.2" -I"C:/Programme/Dev-Cpp/include" -I"C:/Dokumente und Einstellungen/Lars/Desktop/BaseCTest" -pg -g3

In file included from main.cpp:2:
C:/Dokumente und Einstellungen/Lars/Desktop/BaseCTest/baseEngine.h:91: error: invalid return type for function `IBaseInterface BaseCreateFileInfo(char*, bool)'
C:/Dokumente und Einstellungen/Lars/Desktop/BaseCTest/baseEngine.h:91: error: because the following virtual functions are abstract:
C:/Programme/Dev-Cpp/include/unknwn.h:27: error: virtual HRESULT IUnknown::QueryInterface(const IID&, void**)
C:/Programme/Dev-Cpp/include/unknwn.h:28: error: virtual ULONG IUnknown::AddRef()
C:/Programme/Dev-Cpp/include/unknwn.h:29: error: virtual ULONG IUnknown::Release()
C:/Dokumente und Einstellungen/Lars/Desktop/BaseCTest/baseEngine.h:74: error: virtual void* IBaseInterface::GetHandle()

main.cpp: In function `int main(int, char**)':

main.cpp:15: error: cannot allocate an object of type `IBaseInterface'
main.cpp:15: error: since type `IBaseInterface' has abstract virtual functions
main.cpp:15: error: cannot allocate an object of type `IBaseInterface'
main.cpp:15: error: since type `IBaseInterface' has abstract virtual functions
main.cpp:15: error: cannot declare variable `Face' to be of type `IBaseInterface'
main.cpp:15: error: since type `IBaseInterface' has abstract virtual functions
Selbst wenn ich das class durch ein interface ersetze bleibt der fehler.

Apollonius 1. Jun 2009 11:10

Re: Delphi's Interfaces in C++
 
Du musst bedenken, dass Klassen in C++ standardmäßig auf dem Stack abgelegt werden. Grundsätzlich solltest du also überall IBaseInterface durch IBaseInterface* ersetzen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz