ホーム >プログラム >Delphi 6 ローテクTips

WideStringを直接TStringsで持つ

ウムラウトのようなUnicode文字をTStringListに直接持ってしまおうというちょっと外道チックな方法。

始めに

UnicodeとAnsiStringの可逆変換でTStringsは直接WideStringを持つことができないと書きましたが、TStringListならば変則的ではあるものの直接WideStringを持たせることができます。
AddObjectを利用する方法とは違い、WideStringの並びのままのバイト列をコピーしたAnsiStringをセットし、取り出す時はabsolute指令を使います。
AddObjectを利用した場合と比べてオブジェクトを開放する必要がないメリットがあります。
とはいえこのままでOKというわけにはいかず、UTF-8を直接TStringListに持つ場合同様TStringListには持てるけれどもTListBoxやTComboBoxなどではこの方法で持たせることはできません。
それでは使えないじゃないか…とも思ったのですが仮想リストボックスで対処できそうなので、ちょっと面倒ですが読み込みが速くなるなどのメリットもあるので将来のコンポーネント化も視野に入れて実験してみます。

{TMyUStringList}
type
  TMyUStringList = class(TMyWStrings)
  protected
    function WideToAnsi(sStr: WideString): AnsiString; override;
    function AnsiToWide(sStr: AnsiString): WideString; override;
  end;
//------------------------------------------------------------------------------
{TMyUStringList}
function TMyUStringList.WideToAnsi(sStr: WideString): AnsiString;
//WideStringの並びのままのバイト列をAnsiStringとしてコピーして返す
var
  li_Len: Integer;
begin
  li_Len := Length(sStr) +1;
  SetLength(Result, li_Len * 2);
  lstrcpynW(PWideChar(PAnsiChar(Result)), PWideChar(sStr), li_Len);
end;

function TMyUStringList.AnsiToWide(sStr: AnsiString): WideString;
//↑を元に戻す
var
  lp_Src:  PAnsiChar;
  lp_Wide: PWideChar absolute lp_Src;
begin
  lp_Src := PAnsiChar(sStr);
  Result := WideString(lp_Wide);
end;

TMyWStringsを継承したクラスにしているのでTStringsと同じような使い方ができます。


  li_Len := Length(sWStr) +1;
  SetLength(Result, li_Len * 2);
  lstrcpynw(PWideChar(PAnsiChar(Result)), PWideChar(sWStr), li_Len);

SetLengthで領域を確保してlstrcpynWでワイド文字列をコピーしますが、そのときAnsiString型のResultをPAnsiCharとPWideCharで二回キャストするところがミソ。

var
  lp_Str:  PAnsiChar;
  lp_Wide: PWideChar absolute lp_Src;
begin
  lp_Str := PAnsiChar(sStr);
  Result := WideString(lp_Wide);

取り出すときはabsolute指令を使います。
WideString(PWideChar(PAnsiChar(sStr)))はいけることもあるのですがだめな場合もあるので使えません。

ListBoxで使うときはTListBoxのStyleプロパティをlbVirtualやlbVirtualOwnerDrawにした仮想リストボックスにしないと使えません。


2008-06-13: