Migrieren von C++-Code zu mobilen Anwendungen vom Desktop aus

Aus Appmethod Topics
Wechseln zu: Navigation, Suche

Nach oben zu Gesichtspunkte für geräteübergreifende C++-Anwendungen


In diesem Thema wird beschrieben, wie Sie vorhandenen C++-Code, der für Desktop-Plattformen geschrieben wurde, migrieren, sodass er auf mobilen Plattformen verwendet werden kann.

Für mobile Plattformen wurden einige Änderungen an der Object Pascal-Sprache vorgenommen. Viele dieser Änderungen wirken sich auf die Portierung von C++-Code von Desktop-Plattformen zu mobilen Plattformen aus, wie in diesem Thema beschrieben.

Besonderheiten von mobilem C++-Code

Es gibt einige Besonderheiten oder häufige Fehler ("Gotchas"), die Sie beim Entwickeln von C++-Anwendungen für mobile Plattformen oder beim Migrieren von C++-Desktop-Code zu mobilem Code berücksichtigen sollten.

Allgemeines zu String-Typen

Aus den mobilen Object Pascal-Compilern wurden alle String-Typen (wie AnsiString, UTF8String, RawByteString, WideString, ShortString, PAnsiChar usw.) entfernt, mit Ausnahme von System.String, der dem C++-Typ System::UnicodeString zugeordnet ist. C++ für mobile Anwendungen enthält weiterhin die Typen AnsiString, UTF8String, RawByteString und ShortString. Aber die API dieser Typen umfasst nur eine Teilmenge der C++-Versionen dieser Typen für Desktop-Plattformen.

Die folgenden Methoden der Klasse System.AnsiStringT stehen in C++ für mobile Anwendungen nicht zur Verfügung:

Methoden von System.AnsiStringT
(AnsiString, UTF8String, RawByteString),
die nicht für mobile Plattformen verfügbar sind
bool IsPathDelimiter(int index) const
int LastDelimiter(const AnsiStringBase& delimiters) const
TStringMbcsByteType ByteType(int index) const
bool IsLeadByte(int index) const
bool IsTrailByte(int index) const
char* AnsiLastChar() const
static AnsiStringT LoadStr(HINSTANCE hInstance, int ident)
int WideCharBufSize(int codePage) const
wchar_t* WideChar(wchar_t* dest, int destSize, int codePage) const
AnsiStringT& LoadStringW(HINSTANCE hInstance, int ident)

Wie oben bereits erwähnt, wurden PAnsiChar (einspricht in C++ char*) und ShortString aus den mobilen Object Pascal-Compilern entfernt. Diese Änderung ist oft nicht klar und kann zu unerwarteten Ergebnissen führen. Sehen Sie sich zur Klärung die folgenden Beispiele an:

PAnsiChar: TStringBuilder.Append

Da Object Pascal für die mobile Anwendungsentwicklung PAnsiChar nicht unterstützt, wurden die Methoden der Klasse TStringBuilder entfernt, die Argumente vom Typ PAnsiChar akzeptieren:

TStringBuilder* __fastcall Append(const char * Value)/* overload */;
TStringBuilder* __fastcall Append(const System::RawByteString Value)/* overload */;

In diesem Fall arbeitet ähnlicher C++-Code wie der im folgenden Codefragment nicht mehr wie erwartet:

std::auto_ptr<TStringBuilder> sb(new TStringBuilder());
// ...
sb->Append("Hello");

Im obigen Beispiel ruft C++ für mobile Anwendungen die Methode Append, die einen bool-Parameter erwartet, im Hintergrund auf. Dieser Code müsste folgendermaßen lauten, damit er auf Desktop- und mobilen Plattformen funktioniert:

std::auto_ptr<TStringBuilder> sb(new TStringBuilder());
// ...
sb->Append(String("Hello"));

ShortString: TTypeInfo.Name

ShortString wird nicht in Object Pascal für mobile Anwendungen unterstützt. Daher wurden alle Deklarationen, in denen ShortString für Desktop-Plattformen, wie TTypeInfo, verwendet wurde, ebenfalls geändert. Der Member Name ist bei mobilen Anwendungen ein einfacher Byte-Typ. Daher schlägt der folgende C++-Code auf mobilen Plattformen fehl:

static System::UTF8String getTypeInfoName(System::Typinfo::PTypeInfo ti)
{
  return System::UTF8String(ti->Name);
}

Die obige Funktion gibt für mobile Anwendungen im Hintergrund einen String mit einem Byte-Wert, nicht den Namen des Typs, zurück. Der Code müsste folgendermaßen lauten, damit er auf Desktop- und mobilen Plattformen funktioniert:

static System::UTF8String getTypeInfoName(System::Typinfo::PTypeInfo ti)
{
#ifndef _DELPHI_NEXTGEN
  return System::UTF8String(ti->Name);
#else
  int len = ti->Name;
  const char* p = reinterpret_cast<char*>(&(ti->Name));
  return System::UTF8String(p+1, len);
#endif
}

Typumwandlung

In mobilen C++-Anwendungen wird keine C-artige Typumwandlung für Zeiger zu Klassen im Object Pascal-Stil, wie TButton oder TSpeedButton, unterstützt.

Das folgende Codefragment ist beispielsweise falsch:


void Callback(void* p)
{
   ((TButton*)p)->Enable = true;
}

Stattdessen sollten Sie den Operator reinterpret_cast verwenden, der beliebige Zeigertypen in beliebige andere Zeigertypen, sogar von unabhängigen Klassen, konvertiert. Überarbeiten Sie das obige C++Codefragment wie folgt, damit Sie es für mobile C++-Plattformen verwenden können:


void Callback(void* p)
{
    reinterpret_cast<TButton*>(p)->Enable = true;
}

C++11-Features

Die C++-Compiler für iOS (BCCIOSARM und BCCIOSARM64) verwenden die im iOS-SDK enthaltene STL (nicht die Dinkumware Standard-C++-Bibliothek, die von C++-Anwendungen auf Desktop-Plattformen unterstützt wird).

Die C++-Compiler unterstützen nur die C++11-Haupt-Features, die vom BCC64-Compiler implementiert werden. iOS-Compiler unterstützen die C++11-Standardbibliotheks-Features nicht, die für unsere anderen C++-Compiler (in der Win64-Standardbibliothek, in Boost und in C++11-Headern, wie regex, chrono usw.) verfügbar sind.

Weitere Informationen über C++11-spezifische Header finden Sie unter:

Verwenden von starken Aliasen in C++

In früheren Versionen von Object Pascal wurden integrierte Typen, wie NativeInt, NativeUInt und WordBool, integrierten C++-Typen zugeordnet. In neueren Versionen von Object Pascal werden diese Typen als starke Aliase, wie TAlphaColor oder TImageIndex behandelt. Damit C++ mit dieser Änderung kompatibel bleibt, erstellt C++ mit einem Klassen-Wrapper ebenfalls starke Aliase.

Um z. B. NativeInt zu verarbeiten, müssen Sie den Typ explizit angeben (NativeInt). Sehen Sie sich zur Klärung die folgenden Beispiele an:

NativeInt i = 10; // error
NativeInt i = NativeInt(10);  // OK

Verwenden des Operators "delete"

Angenommen Ihr Code enthält den Operator delete:

delete ptr

wobei ptr ein Zeiger auf den freizugebenden Speicherblock ist.

Auf mobilen Plattformen ruft der C++-delete-Operator nicht immer einen Objektdestruktor auf. Der delete-Operator arbeitet folgendermaßen:

  • Wenn ptr auf eine Klasse im Object Pascal-Stil zeigt, dekrementiert der delete-Operator lediglich den Referenzzähler RefCount (die Anzahl von Referenzen auf diese Klasseninstanz). Der Objektdestruktor wird nur aufgerufen, wenn keine Referenzen auf dieses Objekt vorhanden sind.
  • Wenn ptr auf keine Klasse im Object Pascal-Stil zeigt, arbeitet der delete-Operator genauso wie in C++-Anwendungen auf Desktop-Plattformen.

Auflösen von Linker-Warnungen zu String-Literalen

Der folgende Linker-Fehler:

 Error: "__ZN6SystemplEPKwRKNS_13UnicodeStringE", referenced from ...

zeigt an, dass Ihr Code ein wchar_t-Konstantenliteral, das (mit dem +-Operator) einem UnicodeString hinzugefügt wurde, enthält.

Ändern Sie das Konstantenliteral in char16_t, um diesen Fehler zu vermeiden. Verwenden Sie das Makro _D(<Literal-String>) für String-Literale, die mit UnicodeString interagieren.

Ersetzen Sie beispielsweise:

 L"Hello " + System::String("world!")

durch

_D("Hello ") + System::String("world!")

Informationen zu den mobilen Plattformen finden Sie unter Die String-Literale char16_t und wchar_t auf Mac OS X und iOS.

Für mobile Plattformen sind "Defines" erforderlich

Damit Ihr Projekt für mobile Plattformen und Desktop-Plattformen compiliert werden kann, stellen Sie Ihrer Projektimplementierung und den vorcompilierten Header-Dateien (z. B. "Project.cpp" und "ProjectPHC.h") das folgende #ifdef-Fragment voran:

#ifdef _WIN32
  #include <tchar.h>
#else
  typedef char _TCHAR;
  #define _tmain main
#endif

Entfernen Sie FireMonkey-Komponenten, die nicht von den mobilen C++-Compilern unterstützt werden

Komponente für

Desktop-Plattformen

Komponente(n) für
mobile Plattformen
TMainMenu, TPopupMenu TToolBar, TSpeedButton, TPopup


Im Folgenden finden Sie Einzelheiten zum Ersetzen dieser nicht unterstützten Typen.

TMainMenu oder TPopupMenu

Diese Komponenten werden auf mobilen Plattformen nicht unterstützt. Für die Migration Ihres C++-Desktop-Codes zu mobilem Code sollten Sie TMainMenu oder TPopupMenu aus dem Code entfernen und stattdessen die folgenden, auf mobilen Plattformen unterstützten Komponenten verwenden:

So erstellen Sie ein Menü mit TPopup:

  1. Wählen Sie in der Tool-Palette die Komponente TToolBar aus, und ziehen Sie sie in den Formular-Designer.
  2. Wählen Sie in der Tool-Palette die Komponente TSpeedButton aus, und legen Sie sie auf der TToolBar-Komponente ab.
  3. Wählen Sie im Formular- Designer die SpeedButton-Komponente aus, und wählen Sie dann im Objektinspektor in der Eigenschaft StyleLookup den Eintrag buttonstylelabel aus.
  4. Wählen Sie in der Tool-Palette die Komponente TPopup aus, und ziehen Sie sie in den Formular-Designer.
  5. Weisen Sie in der Strukturansicht dieses TPopup als untergeordnetes Element von TSpeedButton zu.
  6. Wählen Sie in der Tool-Palette die Komponente TLabel aus, und ziehen Sie sie in den Formular-Designer.
  7. Weisen Sie in der Strukturansicht dieses TLabel als untergeordnetes Element von TPopup zu.
  8. Wählen Sie die TLabel-Komponente aus, und setzen Sie im Objektinspektor die Eigenschaft HitTest auf True.

Hinweis: Wiederholen Sie die Schritte 6 bis 8, um mehrere Beschriftungen (TLabel) hinzuzufügen.

StructureView.png
  1. Implementieren Sie im Quelltext-Editor für die TSpeedButton-Komponente die folgende onClick-Ereignisbehandlungsroutine:
    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
    {
         // Open the pop-up window.
         Popup1->IsOpen = True;
    }
    
  2. Implementieren Sie für jede TLabel-Komponente, die Sie TPopup hinzugefügt haben, die geeigneten onClick-Ereignisbehandlungsroutinen.


Siehe auch