ホーム >プログラム >Delphi 6 ローテクTips >Unicode文字を含んだファイル名をコンポーネントに渡す

Delphi 6のTMediaPlayerはFileNameがString(AnsiString)なのでウムラウトのようなUnicode文字を含んだファイルを扱えません。
でもなんとかしたい。
ということで頭をひねってなんとか一部解決。


要はカレントディレクトリを移動することと短いファイル名をMediaPlayerに渡すだけなんですけどもね。
メディアプレーヤーに限らずUnicode非対応のコンポーネントにファイルを渡す場合に使える方法かなと。


function gfnbFileExists(sFile: WideString): Boolean;
//Unicode対応のFileExits。
var
  lh_Handle: THandle;
  lr_Info: TWin32FindDataW;
begin
  if (sFile = '') then begin
    Result := False;
  end else begin
    Result := False;

    FillChar(lr_Info, SizeOf(lr_Info), 0);
    lh_Handle:= FindFirstFileW(PWideChar(sFile), lr_Info);
    try
      if (lh_Handle<> INVALID_HANDLE_VALUE) then begin
        repeat
          if  (WideString(lr_Info.cFileName) <> '.')
          and (WideString(lr_Info.cFileName) <> '..')
          and ((lr_Info.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0)
          then begin
            Result := True;
            Break;
          end;
        until not(FindNextFileW(lh_Handle, lr_Info));
      end;
    finally
      Windows.FindClose(lh_Handle);
    end;
  end;
end;

function gfnsFilePathGet(sFile: WideString): WideString;
//Unicode対応のExtractFilePath。
var
  i: Integer;
begin
  Result := '';
  if (sFile <> '') then begin
    for i := Length(sFile) downto 1 do begin
      if (sFile[i] = '\') or (sFile[i] = '/') then begin
        Result := Copy(sFile, 1, i);
        Break;
      end else if (sFile[i] = ':') then begin
        Result := Copy(sFile, 1, i) + '\';
        Break;
      end;
    end;
  end;
end;

function gfnsFileNameGet(sFile: WideString): WideString;
//Unicode対応のExtractFileName。
//拡張子はつく。

var
  i, li_Len, li_Pos: Integer;
begin
  Result := '';
  if (sFile <> '') then begin
    li_Len := Length(sFile);
    li_Pos := li_Len + 1; //sFileの最後が'\'であった場合への対策。
    for i := li_Len downto 1 do begin
      if (sFile[i] = '\') or (sFile[i] = '/') or (sFile[i] = ':') then begin
        Break;
      end;
      li_Pos := i;
    end;
    Result := Copy(sFile, li_Pos, MaxInt);
  end;
end;

function gfnsShortFileNameGet(sFile: WideString): WideString;
{
短いファイル名を返す。
戻り値がWideStringであることに注意。
Unicode非対応のコンポーネントにファイルを渡すときの(完全ではないけれど)逃げ道。
}
var
  lp_Buff: PWideChar;
begin
  Result := sFile;

  lp_Buff := AllocMem((MAX_PATH + 1) * 2);
  try
    if (GetShortPathNameW(PWideChar(sFile), lp_Buff, (MAX_PATH + 1) * 2) > 0) then begin
      Result := WideString(lp_Buff);
    end;
  finally
    FreeMem(lp_Buff);
  end;
end;


procedure MediaOpen(const sWFile: WideString);
//sWFileをMediaPlayerで開く。
var
  ls_WPath, ls_WName: WideString;
begin
  if (gfnbFileExists(sWFile)) then begin
    //ファイルをパスとファイル名部分に分ける。
    ls_WPath  := gfnsFilePathGet(sWFile);
    ls_WName  := gfnsFileNameGet(sWFile);

    //カレントディレクトリをsWFileのあるディレクトリに変更。
    SetCurrentDirectoryW(PWideChar(ls_WPath));

    with MediaPlayer do begin
      //ファイル名を短いファイル名にしてセット。
      FileName := gfnsShortFileNameGet(ls_WName);
      Open;
      Play;
    end;
  end;
end;

まずファイルをパスとファイル名に分けます。
そしてカレントディレクトリをパスに移動します。
このときUnicode対応のWindows APIのSetCurrentDirectoryWを使います。
これでパス部分にウムラウトのようなUnicode文字が含まれていても何の問題もなくなります。
次にファイル名を短いファイル名に変換します。
そしてその変換したファイル名をMediaPlayerのFileNameプロパティに代入します。
あとはOpen, Playでうまくいけば御の字と。

肝はファイルのあるディレクトリをカレントディレクトリにすることと短いファイル名を使うことの二点です。
そのためファイル名にウムラウトのようなUnicode文字が含まれていて、かつ短いファイル名(8.3形式)に合致してしまう場合は変換しても元のUnicode文字を含んだままなのでうまくいきません。
ここがネックです。

あとはカレントディレクトリを変更すると困るプログラムの場合、ファイルをパスとファイル名に分けず一気に短いファイル名に変換して渡すこともできます。その場合カレントディレクトリを移動する場合に比べて成功率は下がりますが、それでもうまくいく場合もあります。