« 2008年11月 | メイン | 2009年01月 »

2008年12月 アーカイブ

2008年12月01日

RAD Studio 2007用とRAD Studio 2009用のIDE Fix Pack 2.1が公開されました。

RAD Studio 2007用とRAD Studio 2009用のIDE Fix Pack 2.1が公開されました。

開発者のAndreas Hausladenさんのブログ

2008年12月10日

第11回 エンバカデロ・デベロッパーキャンプ ? 資料ダウンロード

2008年12月3日、盛況のうちに終了した第11回エンバカデロ・デベロッパーキャンプのプレゼンテーション資料をダウンロードいただけます。

第11回 エンバカデロ・デベロッパーキャンプ ? 資料ダウンロード

第11回 エンバカデロ・デベロッパーキャンプの資料がダウンロードできるようになりました。

参加者の方々のブログを読んでいると面白そうで、参加できなかったことが残念です。

この資料を読んで、勉強します。

TThreadのSynchronizeとQueueについて

第11回 エンバカデロ・デベロッパーキャンプの資料にある「Delphiでのマルチスレッドプログラミング」を読んで。

TThreadの排他制御にSynchronizeの他にQueueという機能がDelphi2005から追加されたそうです。

これは知りませんでしたので、早速試してみました。

まずはSynchronizeから。

//---------------------------------------------------------------------------
void __fastcall TSampleThread::Execute()
{
  FMsg = "Start";
  Synchronize(&WriteMsg);

  FMsg = "End";
  Synchronize(&WriteMsg);
}
//---------------------------------------------------------------------------
void __fastcall TSampleThread::WriteMsg()
{
  Sleep(1000);
  Form1->Memo1->Lines->Add(FMsg);
}

Synchronizeは並行動作ではないため、実行が終わるまでワーカースレッドは待たされます。

実行結果は次のようになります。

Start
End

次に新機能のQueueです。

//---------------------------------------------------------------------------
void __fastcall TSampleThread::Execute()
{
  FMsg = "Start";
  Queue(&WriteMsg);

  FMsg = "End";
  Queue(&WriteMsg);
}
//---------------------------------------------------------------------------
void __fastcall TSampleThread::WriteMsg()
{
  Sleep(1000);
  Form1->Memo1->Lines->Add(FMsg);
}

Queueでは、メインスレッド側の実行は非同期で並行して行われます。

実行結果は次のようになります。

End
End

WriteMsg()の中でSleep(1000)している間に、Execute()でFMsgが"End"に更新されています。

SynchronizeとQueueを上手に使い分けることで、より効率の良いプログラムができそうです。

DataSnap 2009について

第11回 エンバカデロ・デベロッパーキャンプの資料にある「単層から多層アーキテクチャへの遷移」を読んで。

Delphi2009に搭載されたDataSnap 2009は、すごく簡単で便利そう。
非常に強力なコンポーネントのようです。

使ってみたいとは思いますが、DataSnap2009が搭載されているのはEnterprise版かArchitect版で、Professional版では搭載されていませんよね。残念。

C++Builder版では制限があるようです。
C++BuilderにおけるDataSnap 2009のサポートについて

コンポーネント自作テク ニック

第11回 エンバカデロ・デベロッパーキャンプの資料にある「開発効率を飛躍的に高めるコンポーネント自作テク ニック」 を読んで。

すばらしい資料ですね。
自作コンポーネントの作成方法がよくまとまっています。
あまり見かけない情報ですから、大変貴重な資料だと思います。

Delphi/C++Builder オープンソースコンポーネント実践活用法

第11回 エンバカデロ・デベロッパーキャンプの資料にある 「Delphi/C++Builder オープンソースコンポーネント実践活用法」 を読んで。

これもすばらしい。
大変有益な情報です。
ありがとうございます。

紹介されているDelphi/C++Builder用フリーコンポーネント。
時間があったら試してみたいと思います。

JVCLのコンポーネント紹介も助かります。
面白そうなコンポーネントがたくさんありますね。
JCL・JVCLはコンポーネントがたくさんありすぎて、使用を諦めていました。
もう一度挑戦したいと思いました。
JCLのインストール方法で、C++Builderでコンパイルエラーが発生した場合の対処方法についての記載があるのが嬉しいです。

Delphi 2009への既存コード移行のポイント

第11回 エンバカデロ・デベロッパーキャンプの資料にある 「Delphi 2009ではじめるUnicodeアプリケーション - 既存コード移行のポイント」 を読みました。

Delphi 1からDelphi 2007までのバージョンから、Delphi 2009へコードを移行するためのポイントがまとめられています。
各バージョンでの移行作業がわかるすばらしい資料です。

移行しなければならないプログラムがたくさんありますので、大変助かります。
この資料を参考にして、移行作業を行います。

Delphi/C++Builder 2009のUnicodeに関する情報も充実してきました。
そろそろ本格的に2009に乗り換える時期ですね。

2008年12月12日

C++Builder2009におけるStringの変更による既存コードの修正

C++Builder2007まではコンパイルできた次のコードが、C++Builder2009ではコンパイルエラーになります。

String dir = "C:\\日本語.txt";
FILE* f = fopen(dir.c_str(), "rt");

[BCC32 エラー] File1.cpp(14): E2034 'wchar_t *' 型は 'const char *' 型に変換できない
[BCC32 エラー] File1.cpp(14): E2342 パラメータ '__path' は const char * 型として定義されているので wchar_t * は渡せない

StringがAnsiStringからUnicodeStringに変わったため、String#c_str()の返す型がchar*からwchar_t*に変わりました。

fopenには引数にchar*を受け取るfopen(char*)はありますが、wchar_t*を受け取るfopen(wchar_t*)は存在せず、C++Builder2009ではコンパイルエラーになります。

C++Builder2009でも一度AnsiStringに変換するか、_wfopenを使えば、コンパイル可能です。

# AnsiStringに変換
FILE* f = fopen(AnsiString(dir).c_str(), "rt");

# _wfopenを使用
FILE* f = _wfopen(dir.c_str(), L"rt");

AnsiStringに変換した方のコードはfopen(char*)を使用しますが、

FILE* fp = fopen("日本語.txt","rt");
あるいは
std::ifstream file("日本語.txt");
これ、現在のC/C++では正しく 日本語.txt が
オープンできる保証はどこにもないんです。少なくとも言語仕様としては。

東方算程譚

なのだそうです。
コメント欄も勉強になります。
今まで意識したことがありませんでしたが、微妙な問題があるのですね。

C++0xでは、UTF-8, UTF-16, UTF-32の三つのUnicode符号化方式がサポートされる。

C++0x - Wikipedi

C++0xによって、このあたりがどのように変わるのでしょう。

2008年12月16日

Delphi 2009 / C++Builder 2009 Update 2

Delphi 2009 と C++Builder 2009 の Update 2 がリリースされました。

このアップデートに含まれるのは、データベース関連の修正だけです。

リリースノート: Delphi 2009 および C++Builder 2009 Update 2

今回のアップデートはデータベース関連の修正だけとのこと。
こまめに素早く修正がリリースされるのは嬉しいです。
多くの国の言語に対応する必要があったりと、リリース作業は大変だと思いますが、頑張って下さい。

2008年12月20日

Delphi / C++Builder 2009 Help Update 1

Delphi 2009 および C++Builder 2009 Help Update 1 には、ヘルプ システムのバグ修正のほか、改良がいくつか施されています。

リリースノート: Delphi 2009 および C++Builder 2009 Help Update 1

ということで、Delphi / C++Builder 2009 のHelp Update 1がリリースされました。

2008年12月21日

PyScripter 1.9.9.3リリース

PyScripterはPython用の統合開発環境です。
Eclipseよりもずっと軽いのが魅力です。

PyScripter1.9.9.3がリリースされました。

pyscripter - PyScripter Development Site

gettextが組み込まれたため、このバージョンより言語の選択ができるようになりました。

日本語化パッチも必要ありません。いい感じですね。

PyScripter1.9.9.3 - 偏った言語信者の垂れ流し

とのことで、pyscripterのサイトを見てきました。

2008年12月22日

C++のクラス定義を復習する

C++のクラス定義を復習する。

クラス定義の基本形。

class Foo
{
};

内部クラス。クラス定義の中に他のクラスを定義できる。
Javaと違い、外部クラスとの関連はない。

class Outer
{
public:
  class Inner
  {
  public:
    void say()
    {
      std::puts("Hello");
    }
  }:
};

Outer::Inner c;
c.say();

内部クラスによく似たもので、無名クラス。
C言語の無名構造体のC++版。

class Outer
{
public:
  class
  {
  public:
    void say()
    {
      std::puts("Hello");
    };
  } inner;
};

Outer c;
c.inner.say();

クラスは関数内でも定義できる。

int main(int argc, char* argv[])
{
  class Outer
  {
  };
  Outer o;
  return 0;
}

おなじみテンプレートクラス。

template<class T>
class Foo
{
public:
  T data;
};

Foo<int> foo;
foo.data = 1; //dataはint型。

テンプレートには、型パラメータの他に、非型パラメータも定義できる。
非型パラメータはint、short、charなどの整数値か列挙型が使える。

template<class T, int size>
class Foo
{
  T data[size];
};

Foo<int, 10> foo;

内部クラスにもテンプレートを使用できる。

class Outer
{
public:
  template<class T>
  class Inner
  {
  public:
    T data;
  };
};

Outer::Inner<int> c;
c.data = 1; //dataはint型

外部クラスのテンプレートは、内部クラスにも有効。

template<class T>
class Outer
{
public:
  class Inner
  {
  public:
    T data;
  };
};

Outer<int>::Inner c;
c.data = 1; //dataはint型

これを使うと、コンパイル時に内部クラスを一括して設定することができる。

template<class T>
class Outer
{
public:
  class Inner1
  {
    T data;
  };
  class Inner2
  {
    T data;
  };
  class Inner3
  {
    T data;
  };
};

パラメータ化継承。上位クラスをパラメータにすることができる。

template<class SuperClass>
class Foo : public SuperClass
{
};

パラメータ化継承を使うと、柔軟かつ強力なクラス設計ができる。

template<class SuperClass>
class Employee : public SuperClass
{
};

template<class SuperClass>
class Customer : public SuperClass
{
};

template<class SuperClass>
class Shareholder : public SuperClass
{
};

class Person
{
};

Employee<Person> a;
Shareholder<Employee<Person> > b;
Shareholder<Employee<Customer<Person> > > c;

クラスの設計情報をパラメータ化することもできる。

struct ConfigA
{
  typedef int Price;
};

struct ConfigB
{
  typedef double Price;
};

template<class Config>
class Product : public Config
{
public:
  typedef typename Config::Price Price;
  Price price;
};

Product<ConfigA> a;
a.price = 1; //priceはint型
Product<ConfigB> b;
b.price = 2.3; //priceはdouble型

2008年12月24日

C++のテンプレートはパラメータとして関数をとることができる

C++のテンプレートはパラメータとして関数をとることができる。

/**
 * 3倍する
 */
int treble(int x)
{
  return x * 3;
}
/**
 * 4倍する
 */
int quadruplicate(int x)
{
  return x * 4;
}
/**
 * 引数を計算式で計算する
 * @param function int型の引数をとりint型を返す関数
 * @param a 計算する値
 * @return 計算結果
 */
template<int function(int)>
int calc(int a)
{
  return function(a);
}

//2を3倍する
int num1 = calc<treble>(2);
//3を4倍する
int num2 = calc<quadruplicate>(3);

パラメータ継承を使ったテンプレートメソッド

まずパラメータ継承を使わないテンプレートメソッド。
Wikipediaの例を参考にした。
StringListerで定義されている抽象メソッドformatItem()が、display()内で使われている。

class StringLister
{
public:
  virtual std::string formatItem(std::string item) = 0;
  void display(std::string item)
  {
    std::cout << formatItem(item) << std::endl;
  }
};
class PlainTextStringLister : public StringLister
{
public:
  virtual std::string formatItem(std::string item)
  {
    return "- " + item;
  }
};
class HtmlStringLister : public StringLister
{
public:
  virtual std::string formatItem(std::string item)
  {
    return "<li>" + item + "</li>";
  }
};

PlainTextStringLister().display("Foo"); //=> - Foo
HtmlStringLister().display("Foo");      //=> <li>Foo</li>

パラメータ継承を使ったテンプレートメソッド。
ConcreteClassのメソッドformatItem()が、display()内で使われている。

template<class ConcreteClass>
class StringLister : public ConcreteClass
{
public:
  void display(std::string item)
  {
    std::cout << ConcreteClass::formatItem(item) << std::endl;
  }
};
class PlainTextStringLister
{
protected:
  static std::string formatItem(std::string item)
  {
    return "- " + item;
  }
};
class HtmlStringLister
{
protected:
  static std::string formatItem(std::string item)
  {
    return "<li>" + item + "</li>";
  }
};

StringLister<PlainTextStringLister>().display("Foo"); //=> - Foo
StringLister<HtmlStringLister>().display("Foo");      //=> <li>Foo</li>

2008年12月26日

C++Builder2009におけるWin32APIのWideString版を呼び出す方法

C++Builder2009では文字列がUnicode文字列に変更された。
この変更に伴い、Win32APIの呼び出しも変更された。
ヘルプには次のように記載されている。

API はデフォルトで WideString("W")版を呼び出します。

ms-help://embarcadero.rs2009/devcommon/unicodeinide_xml.html

ところが実際は、「プロジェクトオプション」の「ディレクトリと条件定義」で「_TCHARのマップ先」を「char」から「wchar_t」に変更する必要がある。
ヘルプの「_TCHAR のマップ先」の項目には次のように記載されている。

[wchar_t] を選択すると、以下のように動作します。

  • UNICODE と _UNICODE が定義されます。
  • リンカはワイド バージョンのライブラリを使用します。
  • 標準ライブラリと Windows API の関数は、ワイド定義に設定されます。

ms-help://embarcadero.rs2009/devcommon/dirconditionals_xml.html

「_TCHARのマップ先」の初期値は「char」であるため、WideString版のAPIは呼び出されない。
初期値が「wchar_t」なら、ヘルプの記載も正しいのだが。

2008年12月29日

AnsiStringTのコンストラクタの挙動を調べる

AnsiStringTのコンストラクタにchar*とwchar_t*を引数とした場合の挙動のテスト

const char* c1 = "テスト";
AnsiStringT<20932> euc1(c1);
ShowCode(euc1);

const wchar_t* c2 = L"テスト";
AnsiStringT<20932> euc2(c2);
ShowCode(euc2);

実行結果

CodePage = 20932
83 65 83 58 83 67
CodePage = 20932
a5 c6 a5 b9 a5 c8

char*の場合は変換されず、コードページと文字が一致していない。
コードページはEUC-JPだが、Shift_JISのバイト列のままである。

wchar_t*を引数とした場合は、EUC_JPに変換されている。

代入の場合も同じ動作となる。

今回の検証に使用した関数

void ShowCode(const RawByteString& Str)
{
  printf("CodePage = %d\n", StringCodePage(Str));
  for (int i = 1; i <= Str.Length(); i++)
  {
    printf("%x ", static_cast<unsigned char>(Str[i]));
  }
  printf("\n");
}

AnsiStringTの代入の挙動を調べる

AnsiStringTからコードページの異なるAnsiStringTへの代入のテスト

AnsiStringT<932> sjis = L"テスト";
AnsiStringT<20932> euc = sjis;
ShowCode(euc);

実行結果

CodePage = 20932
a5 c6 a5 b9 a5 c8

コードページにしたがって変換されている。

UnicodeStringを間に挟んだ場合のテスト

AnsiStringT<932> sjis = L"テスト";
UnicodeString uni = sjis;
AnsiStringT<20932> euc = uni;
ShowCode(euc);

実行結果

CodePage = 20932
a5 c6 a5 b9 a5 c8

Shift_JISからEUC-JPに変換されている。

結論としては、
AnsiStringTからAnsiStringTへの代入、
AnsiStringTからUnicodeStringへの代入、
UnicodeStringからAnsiStringTへの代入、
は、いずれも自動的に変換されるようだ。

今回の検証に使用した関数

void ShowCode(const RawByteString& Str)
{
  printf("CodePage = %d\n", StringCodePage(Str));
  for (int i = 1; i <= Str.Length(); i++)
  {
    printf("%x ", static_cast<unsigned char>(Str[i]));
  }
  printf("\n");
}

RawByteStringの動作のテスト

RawByteStringの動作のテスト

RawByteStringのコンストラクタのテスト

char*を受け取るコンストラクタ

RawByteString raw("テスト");
ShowCode(raw);

実行結果

CodePage = 65535
83 65 83 58 83 67

バイト列をそのまま変換しないで保持している。

wchar_t*を受け取るコンストラクタ

RawByteString raw(L"テスト");
ShowCode(raw);

実行結果

CodePage = 932

値が空になっている。
RawByteString(wchar_t*)は引数が無効になるので注意が必要だ。

代入のテスト

const wchar_t* c = L"テスト";
AnsiStringT<20932> euc(c);
RawByteString raw = euc;
ShowCode(raw);

実行結果

CodePage = 20932
a5 c6 a5 b9 a5 c8

コードページも文字のバイト列も変換しないで、そのまま保持している。

UnicodeString uni = "テスト";
RawByteString raw = uni;
ShowCode(raw);

実行結果

CodePage = 932

UnicodeStringをRawByteStringに代入すると空になる。
wchar_t*を引数にとるコンストラクタと同じ挙動だ。

今回の検証に使用した関数

void ShowCode(const RawByteString& Str)
{
  printf("CodePage = %d\n", StringCodePage(Str));
  for (int i = 1; i <= Str.Length(); i++)
  {
    printf("%x ", static_cast<unsigned char>(Str[i]));
  }
  printf("\n");
}

About 2008年12月

2008年12月にブログ「山本隆の開発日誌」に投稿されたすべてのエントリーです。過去のものから新しいものへ順番に並んでいます。

前のアーカイブは2008年11月です。

次のアーカイブは2009年01月です。

他にも多くのエントリーがあります。メインページアーカイブページも見てください。

Powered by
Movable Type 3.35