Visual C++ 2008 Express Editionでアプリを作る(その12)

油断大敵。
最後は指定フォルダへの移動を実装すれば完成です。File::MoveとDirectory::Moveを使えばスグに終わると思っていました。サクッとコードを書いて、テストをしてみると例外が発生する。msdnによると、どうも

たとえば、c:\mydir を c:\public に移動しようとしたところ、c:\public が既に存在する場合、このメソッドは IOException をスローします。"c:\\public" の下に "mydir" が存在しない場合は、destDirName パラメータとして "c:\\public\\mydir" を指定する必要があります。または、"c:\\newdir" などの新しいディレクトリ名を指定します。

に対応する必要があるらしい。んもー、使いづらい。しゃーないので、同じようにWindows APIを使う事にした。ちゃんと実装するのが面倒なのはわかるけどさぁ。下に書いた\を\\に置換するのも、条件を考えないと不具合が発生するハズ。

extern "C" {
int MyMoveToFolder(LPCTSTR file, LPCTSTR folder_path) {
  SHFILEOPSTRUCT sh_file_operation_struct;
  int result = 1;
  LPTSTR file_copied = (LPTSTR)calloc(lstrlen(file) + 2, sizeof(TCHAR));
  LPTSTR file_to = (LPTSTR)calloc(lstrlen(folder_path) + 2, sizeof(TCHAR));
  FILEOP_FLAGS   flags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;

  lstrcpy(file_copied, file);
  lstrcpy(file_to, folder_path);

  ZeroMemory( &sh_file_operation_struct, sizeof(sh_file_operation_struct) );
  sh_file_operation_struct.wFunc  = FO_MOVE;
  sh_file_operation_struct.fFlags = flags;
  sh_file_operation_struct.pFrom  = file_copied;
  sh_file_operation_struct.pTo    = file_to;

  result = SHFileOperation(&sh_file_operation_struct);
  free(file_copied);
  free(file_to);
  return result;
}
};

int FileTool::MoveToFolder(String ^srcpath, String ^dstpath)
{
  int result = 1;
  LPCTSTR src, dst;
  //¥を¥¥に置換する
  String^ folderPath = dstpath->Replace("\\", "\\\\");
  Diagnostics::Trace::WriteLine(folderPath);

  IntPtr p = System::Runtime::InteropServices::Marshal::StringToHGlobalAuto(srcpath);
    src = static_cast<LPCTSTR>(p.ToPointer());
  IntPtr q = System::Runtime::InteropServices::Marshal::StringToHGlobalAuto(folderPath);
    dst = static_cast<LPCTSTR>(q.ToPointer());
  try {
    result = MyMoveToFolder(src, dst);
  } finally {
    System::Runtime::InteropServices::Marshal::FreeHGlobal(p);
    System::Runtime::InteropServices::Marshal::FreeHGlobal(q);
  }
  return result;
}