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

Aus Appmethod Topics
Wechseln zu: Navigation, Suche

Nach oben zu Mobile iOS-Anwendungsentwicklung

Nach oben zu Mobile Android-Anwendungsentwicklung


An der Object Pascal-Sprache wurden für die Entwicklung mobiler Apps einige Änderungen vorgenommen. Viele dieser Änderungen beziehen sich auf das Portieren von C++-Desktop-Code zu mobilem Code.
In diesem Thema wird beschrieben, wie Sie vorhandenen C++-Desktop-Code für die Verwendung der mobilen C++-Compiler migrieren:

Zu C++-Desktop-Anwendungen zählen auch diejenigen, die für die folgenden C++-Desktop-Compiler geschrieben wurden:

Besonderheiten von mobilem C++-Code

Es gibt einige Besonderheiten oder häufige Fehler ("Gotchas"), die Sie beim Entwickeln von mobilen C++-Anwendungen 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 werden kann. C++ für mobile Anwendungen enthält weiterhin die Typen AnsiString, UTF8String, RawByteString und ShortString. Aber dieser Typ von APIs umfasst nur eine Teilmenge von den C++-Desktop-Versionen dieser Typen.

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 Apps 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 von den mobilen Object Pascal-Compliern 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 auch alle Deklarationen, in denen ShortString für Desktop-Anwendungen, 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 in einer mobilen App 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 Codefragment wie folgt, damit Sie es für mobile C++-Apps verwenden können:

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

C++11-Features

Der C++-Compiler für iOS (BCCIOSARM.exe) verwendet die im iOS-SDK enthaltene STL (nicht die Dinkumware Standard-C++-Bibliothek, die von C++-Desktop-Anwendungen unterstützt wird).

Der BCCIOSARM-Compiler unterstützt nur die C++11-Haupt-Features, die vom BCC64-Compiler implementiert werden. BCCIOSARM unterstützt die C++11-Standardbibliotheks-Features nicht, die für unsere anderen C++-Compiler (in der Win64-Standardbibliothek, in den Boost-Bibliotheken 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, zu 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.

Wenn Sie beispielsweise NativeInt 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.

In C++ für mobile Apps ruft der 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 eine Klasse zeigt, die nicht im Object Pascal-Stil vorliegt, arbeitet der delete-Operator genauso wie in C++ für Desktop-Anwendungen.

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 über mobile Plattformen finden Sie unter Die String-Literale char16_t und wchar_t auf der OS X-Plattform.

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-Anwendungen

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


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

TMainMenu oder TPopupMenu

Diese Komponenten werden in mobilen Anwendungen nicht unterstützt. Für die Migration Ihres C++-Desktop-Codes zu mobilem Code sollten Sie TMainMenu oder TPopupMenu aus Ihrem Code entfernen und stattdessen die folgenden, in mobilen Anwendungen 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 Designer für mobile FireMonkey-Formulare.
  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 Designer für mobile FireMonkey-Formulare 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 Designer für mobile FireMonkey-Formulare.
  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 Designer für mobile FireMonkey-Formulare.
  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