デスクトップ アプリケーションからモバイル アプリケーションへの C++ コードの移行

提供: RAD Studio
移動先: 案内検索

C++ におけるマルチデバイス アプリケーションについての考慮事項 への移動


このトピックでは、デスクトップ プラットフォーム用に記述された既存の C++ コードを、モバイル プラットフォームで動作するように移行する方法について説明します。

Delphi 言語はモバイル プラットフォーム用に少し変更されました。 これらの変更の多くは、このトピックで説明するように、デスクトップ プラットフォームからモバイル プラットフォームへ C++ コードを移行する際に影響を及ぼします。

C++ モバイル コードの特性

モバイル プラットフォームの C++ アプリケーションの開発時や C++ デスクトップ コードからモバイル コードへの移行時に考慮しなければならない特性がいくつかあります。

文字列型に関して

Delphi のモバイル コンパイラでは、System.String は C++ の System::UnicodeString 型にマッピングされ、それ以外の文字列型(AnsiString、UTF8String、RawByteString、WideString、ShortString、PAnsiChar など)はすべて削除されました。C++ モバイル コンパイラには、まだ AnsiString、UTF8String、RawByteString、ShortString が用意されています。しかし、これらの型の API はデスクトップ プラットフォームのそれらの C++ 版で提供される API の一部になります。

System.AnsiStringT クラスの以下のメソッドは C++ モバイル コンパイラでは使用できません。

モバイル プラットフォームで使用できない
System.AnsiStringT(AnsiString、UTF8String、RawByteString)
のメソッド
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)

先に述べたように、Delphi モバイル コンパイラでは、PAnsiChar(C++ では、char* に相当)と ShortString が削除されました。その変更は一目瞭然でないことが多く、予期しない結果につながるおそれがあります。この点を明確にするために、以下のような例を考えてみましょう。

PAnsiChar:TStringBuilder.Append

Delphi モバイル コンパイラでは PAnsiChar をサポートしていないため、TStringBuilder クラスのメソッドで PAnsiChar 型の引数を受け取るもの(下記)は削除されました。

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

この場合は、次のコード断片のような C++ コードはもう期待どおりには動作しません。

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

上記の例では、C++ モバイル コンパイラは、bool 型のパラメータを受け取る Append メソッドをメッセージなしに呼び出します。このコードがデスクトップ プラットフォームでもモバイル プラットフォームでも動作するには、次のように書かなければなりません。

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

ShortString:TTypeInfo.Name

ShortString は、Delphi モバイル版ではサポートされていません。そのため、TTypeInfo のように、デスクトップ プラットフォームで ShortString を使用していた宣言もすべて変更されました。Name メンバは、モバイル版では普通の Byte 型になります。つまり、次の C++ コードはモバイル プラットフォームでは動作しません。

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

上記の関数は、モバイル コンパイラ上では、型の名前ではなく Byte 値の文字列をメッセージなしに返します。このコードがデスクトップ プラットフォームでもモバイル プラットフォームでも動作するには、次のように書かなければなりません。

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
}

型キャストに関して

C++ モバイル コンパイラでは、TButtonTSpeedButton などの Delphi 形式のクラスを指すポインタの C 言語のようなキャストをサポートしていません。

たとえば、次のようなコードは間違いです。

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

代わりに、reinterpret_cast 演算子を使用しなければなりません。この演算子は任意のポインタ型を他の任意のポインタ型(無関係なクラスのポインタでも可)に変換します。上記の C++ コードをモバイル プラットフォームに使用するには、次のように書き直します。

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

C++11 機能に関して

iOS 用の C++ コンパイラ(BCCIOSARM および BCCIOSARM64)では、(デスクトップ プラットフォームの C++ アプリケーションでサポートされている Dinkumware 標準 C++ ライブラリではなく)iOS SDK に付属している STL を使用します。

iOS 用 C++ コンパイラでは、BCC64 コンパイラで実装されている C++11 のコア機能のみサポートしています。 iOS コンパイラは、標準 C++11 ライブラリ機能をサポートしていません。これは、当社の他の C++ コンパイラ(Win64 ライブラリ、Boost ライブラリ、C++11 ヘッダー内にある、regexchrono、など)で利用できる機能です。

C++11 固有のヘッダーの詳細については、以下を参照してください。

C++ の強いエイリアスの使用

Delphi の以前のバージョンでは、NativeIntNativeUIntWordBool などの組み込み型を C++ の組み込み型にマッピングしていました。Delphi の新しいバージョンでは、これらの型を強いエイリアスとして扱っています(TAlphaColorTImageIndex など)。このような変更に対応するために、C++ でもクラス ラッパーを使って強いエイリアスを作成します。

たとえば、NativeInt を扱うには、型(NativeInt)を明示的に指定する必要があります。この点を明確にするために、次のような場合を考えてみましょう。

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

delete 演算子の使用

次のように、コードに delete 演算子が含まれているとしましょう。

delete ptr

ここで、ptr は、解放するメモリ ブロックのポインタです。

モバイル プラットフォームでは、C++ の delete 演算子は必ずしもオブジェクトのデストラクタを呼び出すわけではありません。delete 演算子は次のように動作します。

  • ptr が Delphi 形式のクラスを指している場合、delete 演算子は RefCount(このクラス インスタンスへの参照回数)をデクリメントするだけです。オブジェクトのデストラクタは、このオブジェクトへの参照が他にない場合にのみ呼び出されます。
  • ptr が Delphi 形式でないクラスを指している場合、delete 演算子の動作はデスクトップ プラットフォームの C++ アプリケーションの場合とちょうど同じです。

文字列リテラルに関するリンカの警告の解決

次のようなエラーがリンカから出力される場合は、

 Error: "__ZN6SystemplEPKwRKNS_13UnicodeStringE", referenced from ...

+ 演算子により)UnicodeString に付加されている wchar_t 定数リテラルがコードに含まれていることを示しています。

これを回避するには、この定数リテラルを char16_t に切り替えます。UnicodeString とやり取りする文字列リテラルの場合には、_D(<リテラル文字列>) マクロを使用することをお勧めします。

たとえば、次のコードを

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

次のコードに置き換えます。

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

モバイル プラットフォームについては、「OS X プラットフォームでの文字列リテラル char16_t と wchar_t」を参照してください。

モバイル プラットフォームには条件定義が必要

プロジェクトをデスクトップ プラットフォームだけでなくモバイル プラットフォーム向けにもコンパイルできるようにするには、プロジェクトの実装ファイルとプリコンパイル済みヘッダー ファイル(たとえば "Project.cpp" と "ProjectPHC.h")の前に、次のような #ifdef ブロックを付け加える必要があります。

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

C++ モバイルでサポートされていない FireMonkey コンポーネントを削除

デスクトップ アプリケーションで
使用されているコンポーネント
モバイル プラットフォームで
使用するコンポーネント
TMainMenuTPopupMenu TToolBarTSpeedButtonTPopup


サポートされていないこれらの型の置き換えの詳細については、以下で説明します。

TMainMenu または TPopupMenu

これらのコンポーネントは、モバイル プラットフォームではサポートされていません。C++ デスクトップ コードをモバイルに移行するには、TMainMenu または TPopupMenu をコードから削除し、モバイルでサポートされている以下のコンポーネントを代わりに使用しなければなりません。

TPopup を使用するメニューを作成するには:

  1. [ツール パレット]TToolBar コンポーネントを選択して、フォーム デザイナにドロップします。
  2. [ツール パレット]TSpeedButton コンポーネントを選択し、上記のツールバー上にドロップします。
  3. フォーム デザイナで SpeedButton コンポーネントを選択したあと、[オブジェクト インスペクタ]StyleLookup プロパティの値フィールドから[buttonstylelabel]を選択します。
  4. [ツール パレット]TPopup コンポーネントを選択して、フォーム デザイナにドロップします。
  5. [構造]ビューで、この TPopup を TSpeedButton の子にします。
  6. [ツール パレット]TLabel コンポーネントを選択して、フォーム デザイナにドロップします。
  7. [構造]ビューで、この TLabel を TPopup の子にします。
  8. [オブジェクト インスペクタ]で TLabel を選択し、HitTest プロパティを True に設定します。

メモ: ラベルを複数追加する場合は、ステップ 6 ~ 8 を繰り返します。

StructureView.png
  1. コード エディタで、TSpeedButton コンポーネントに対して以下の onClick イベント ハンドラを実装します。
    void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
    {
         // Open the pop-up window.
         Popup1->IsOpen = True;
    }
    
  2. TPopup に追加した TLabel コンポーネントごとに、適切な onClick イベント ハンドラを実装します。


関連項目