Migrating C++ Code to Mobile from Desktop

From Appmethod Topics
Jump to: navigation, search

Go Up to C++ Considerations for Multi-Device Applications

This topic describes how to migrate existing C++ code written for desktop platforms so that it works on mobile platforms.

The Object Pascal language has undergone some changes for mobile platforms. Many of these changes affect porting C++ code from desktop platforms to mobile platforms, as described in this topic.

Peculiarities of C++ Mobile Code

There are some peculiarities or "gotchas" that you should consider when you are developing your C++ applications for mobile platforms or when you are migrating C++ desktop code to mobile code.

About String Types

Object Pascal's mobile compilers eliminated all string types (such as AnsiString, UTF8String, RawByteString, WideString, ShortString, PAnsiChar, and so forth) except for System.String, which maps to the C++ System::UnicodeString type. C++ Mobile still provides AnsiString, UTF8String, RawByteString and ShortString. But the API of these types is a subset of that provided in the C++ versions of these types for desktop platforms.

The following methods of the System.AnsiStringT class are not available in С++ Mobile:

Methods of System.AnsiStringT
(AnsiString, UTF8String, RawByteString)
that are not available in mobile platforms
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)

As mentioned above, Object Pascal mobile compilers eliminated PAnsiChar (in C++, it corresponds to char*) and ShortString. That change is often not obvious and can lead to unexpected results. To clarify, consider the following examples:

PAnsiChar: TStringBuilder.Append

Because Object Pascal mobile does not support PAnsiChar, the methods of the TStringBuilder class that accept arguments of the PAnsiChar type have been removed:

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

In this case, C++ code that is similar to the following code snippet no longer works as expected:

std::auto_ptr<TStringBuilder> sb(new TStringBuilder());
// ...

In the above example, C++ mobile silently invokes the Append method that expects a bool parameter. To work on both desktop and mobile platforms, this code should be written as follows:

std::auto_ptr<TStringBuilder> sb(new TStringBuilder());
// ...

ShortString: TTypeInfo.Name

ShortString is not supported in Object Pascal mobile. So any declarations that used ShortString on desktop platforms, like TTypeInfo, have also changed. The Name member is a plain Byte on Mobile. This means that the following C++ code fails in mobile platforms:

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

The above function, on mobile, silently returns a string with a Byte value, not the name of the type. To work on both desktop and mobile platforms, the code should be written as follows:

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

About Type Casting

C++ mobile does not support C-like casting for pointers to Object Pascal-style classes, such as TButton or TSpeedButton.

For example, the following code snippet is incorrect:

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

Instead, you should use the reinterpret_cast operator, which converts any pointer type to any other pointer type, even of unrelated classes. To use the above C++ code snippet for mobile platforms, rework it as follows:

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

About C++11 Features

The C++ compilers for iOS (BCCIOSARM and BCCIOSARM64) use the STL included with the iOS SDK (not the Dinkumware Standard C++ Library, which is supported by C++ applications on desktop platforms).

The C++ compilers for iOS support only the core C++11 features that are implemented by the BCC64 compiler. iOS compilers do not support the standard C++11 library features, which are available for our other C++ compilers (in the Win64 standard library, in the Boost, and in C++11 headers, such as regex, chrono, and so forth).

For more information about C++11-specific headers, see:

Using C++ Strong Aliases

Earlier versions of Object Pascal mapped built-in types such as NativeInt, NativeUInt, and WordBool to C++ built-in types. Newer versions of Object Pascal handle these types as strong aliases, such as TAlphaColor or TImageIndex. In order to be compatible with the change, C++ also creates strong aliases using a class wrapper.

For example, to handle a NativeInt, you need to explicitly specify the type (NativeInt). To clarify, consider the following cases:

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

Using the delete Operator

Let us consider that your code contains the delete operator:

delete ptr

where ptr is a pointer to the memory block to be released.

In mobile platforms, the C++ delete operator does not always call an object destructor. The delete operator works in the following way:

  • If ptr points to a Object Pascal-style class, the delete operator merely decrements the RefCount (the number of references to this class instance). The object destructor is invoked only if there are no other references to this object.
  • If ptr points to a non-Object Pascal-style class, the delete operator works exactly the way it does in a C++ application on desktop platforms.

Resolving Linker Warnings about String Literals

The following error from the linker:

 Error: "__ZN6SystemplEPKwRKNS_13UnicodeStringE", referenced from ...

indicates that your code contains a wchar_t constant literal being added (via the + operator) to a UnicodeString.

The workaround is to switch the constant literal to a char16_t. We recommend that you use the _D(<lit-string>) macro for string literals interacting with UnicodeSTring.

For example, replace:

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


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

For information about the mobile platforms, see String Literals char16_t and wchar_t on the OS X Platform.

Defines Required for Mobile Platforms

To make your project compile for mobile platforms as well as desktop platforms, prepend your project implementation and precompiled header files (for example, "Project.cpp" and "ProjectPHC.h") with the following #ifdef snippet:

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

Eliminate FireMonkey Components that Are Not Supported on C++ Mobile

Component Used in

Desktop Platforms

Component(s) to Use in
Mobile Platforms
TMainMenu, TPopupMenu TToolBar, TSpeedButton, TPopup

Details follow about replacing these unsupported types.

TMainMenu or TPopupMenu

These components are not supported in mobile platforms. To migrate your C++ desktop code to mobile, you should remove TMainMenu or TPopupMenu from your code, and use instead the following mobile-supported components:

To create a menu that uses TPopup

  1. Select the TToolBar component in the Tool Palette, and drop it on the Form Designer.
  2. Select the TSpeedButton component in the Tool Palette and drop it on the ToolBar.
  3. Select the SpeedButton component on the Form Designer, and then select buttonstylelabel in the StyleLookup property in the Object Inspector.
  4. Select the TPopup component in the Tool Palette, and drop it on the Form Designer.
  5. In the Structure View, make this TPopup a child of the TSpeedButton.
  6. Select the TLabel component in the Tool Palette, and drop it on the Form Designer.
  7. In the Structure View, make this TLabel a child of the TPopup.
  8. Select the TLabel, and in the Object Inspector, set the HitTest property to True.

Note: To add several labels, repeat Steps 6 to 8.

  1. In the Code Editor, for the TSpeedButton component, implement the following onClick event handler:
    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
         // Open the pop-up window.
         Popup1->IsOpen = True;
  2. For each TLabel component that you have added to the TPopup, implement the appropriate onClick event handlers.

See Also