TeraCopyをコマンドラインから呼び出す(その2)

どうも職場のPC自体がおかしいので、TeraCopyが正常に動作していなかったらしい。エクスプローラーから操作しても現象が変わらなかった。なので、前回作ったバッチファイルに罪は無い。
モチベーションが下がってしまったけど、続ける。

まず、前回までに書いたコードに不具合があった。argcは4以上が正常な動作だった。あと、usage()でexit(-1)としているのは行儀が悪い。

#define ARGC_CMD 1 // argvでteracopyのコマンド(COPY|MOVE)がある位置

void usage(void)
{
  _tprintf(_T("teracopy_wrap.exe (COPY|MOVE) source target\n"));
  exit(-1);
}

int _tmain(int argc, _TCHAR* argv[])
{
  // 調査用
  printf("argc: %d\n", argc);
  for (int i = 1; i < argc; i++) {
    _tprintf(_T("argv[%d]: %s\n"), i, argv[i]);
  }
  if (argc < 4) {
    // エラーメッセージ
    usage();
  }
  if (_tcsicmp(_T("copy"), argv[ARGC_CMD]) == 0 ||
    _tcsicmp(_T("move"), argv[ARGC_CMD]) == 0) {
    teracopy(argc, argv); // COPY | MOVE
  } else {
    usage(); // エラー
  }
  return 0;
}

まず、TMPフォルダ以下に作成する一時ファイル名を取得する関数を作っておいた。UNICODEでの最大長定義がなさそうだったので、暫定で定義した。

#define UMAX_PATH 32767 // UNICODEでのpath最大長定義(見つからないので)
int getTmpFilePath(TCHAR* path)
{
  TCHAR TmpPath[UMAX_PATH];
  GetTempPath(UMAX_PATH, TmpPath);
  GetTempFileName(TmpPath, _T("tcw"), 0, path);
  return 0;
}

teracopy()はコマンド引数を解釈を行って、実行部exec_cmd()にパラメータを渡す。一時ファイルのパス名の先頭に「\\?\」をつけると、ディレクトリ区切り文字の「\」をそのまま解釈してくれる*1ので、横着してファイルopen時に使った。
あと、argvのポインタをstargに代入しているのも本当は良くない。

typedef struct {
  _TCHAR *cmd;
  _TCHAR *src;
  _TCHAR *trg;
} stArgument;

void teracopy(int argc, _TCHAR* argv[])
{
  TCHAR TmpFilePath[UMAX_PATH] = {NULL};
  TCHAR TmpPath[UMAX_PATH];
  stArgument starg;

  // コマンド解釈部
  if (argc == 4) {
    starg.cmd = argv[ARGC_CMD];
    starg.src = argv[ARGC_CMD + 1];
    starg.trg = argv[ARGC_CMD + 2];
  } else {
    FILE *fp;
    errno_t err;

    getTmpFilePath(TmpFilePath);

    // \\?\から始まるパス名 拡張機能
    _stprintf_s(TmpPath, sizeof(TCHAR) * UMAX_PATH, _T("\\\\?\\%s"), TmpFilePath);
    err = _tfopen_s(&fp, TmpPath, _T("w"));
    if (err != 0) {
      _tprintf(_T("teracopy_wrap:can not open tmpfile.\n"));
      exit(-1);
    }
    for (int i = ARGC_CMD + 1; i < argc - 1; i++) {
      _ftprintf_s(fp, _T("%s\n"), argv[i]);
    }
    fclose(fp);

    _stprintf_s(TmpPath, sizeof(TCHAR) * UMAX_PATH, _T("*%s"), TmpFilePath);
    starg.cmd = argv[ARGC_CMD];
    starg.src = TmpPath;
    starg.trg = argv[argc -1];
  }
  exec_cmd(&starg);
  if (TmpFilePath != NULL) {
    DeleteFile(TmpFilePath);
  }
}

*1:他の副作用もあるのだけど