HFileOperationを使用してディレクトリを削除するには?

解決


田中  2009-08-09 06:19:46  No: 70777

田中と申します、WinXP + VC++6.0環境でプログラムしています。

SHFileOperationを利用して中に含まれるファイルごとディレクトリを削除し
ようと思い、書籍やサイトを参考にして以下のテストプログラムで一応削除
には成功しました。

/////////////////////////////////////////

SHFILEOPSTRUCT str;
memset(&str,0,sizeof(str));

str.hwnd = NULL;  
str.wFunc = FO_DELETE; 
str.pFrom = "D:\\test10\\Test";  //削除先 
str.fFlags=FOF_SIMPLEPROGRESS|FOF_NOCONFIRMATION;

SHFileOperation(&str);
 
/////////////////////////////////////////

しかし実際に使用する場合には、削除先を表す文字列の作成にCString型の戻
り値を使用しなければならないため、試行錯誤してみたのですがどうしても
成功することができません。
最終的に以下のテストプログラムでビルドエラーは出なくなったのですが、
実行時に「ファイルを削除できません。送り側のファイルまたはディスクから
読み取れません。」というエラーが表示されてしまいす。
アドバイスいただければ幸いです。よろしくお願いいたします。

///////////////////////////////////////////

  CString s1 = "D:\\\\";
  CString s2 = "test";

  char c1[100];
  char c2[100];

  lstrcpy(c1, s1);
  lstrcpy(c2, s2);

  lstrcat(c1, "test10\\\\");
  lstrcat(c1, c2);

  SHFILEOPSTRUCT str;
  memset(&str,0,sizeof(str));

  str.hwnd = NULL;  
  str.wFunc = FO_DELETE; 
  str.pFrom = (LPCSTR) c1;  //削除先 
  str.fFlags=FOF_SIMPLEPROGRESS|FOF_NOCONFIRMATION;

  SHFileOperation(&str);

//////////////////////////////////////////////


...  2009-08-09 11:18:36  No: 70778

> 実行時に「ファイルを削除できません。送り側のファイルまたはディスクから
> 読み取れません。」というエラーが表示されてしまいす。

実行時に該当フォルダが無いからでしょう。
実行直前にでもD:\test10\testを作成して下さい。


田中  2009-08-09 18:20:23  No: 70779

Resをありがとうございます。

>実行時に該当フォルダが無いからでしょう。
>実行直前にでもD:\test10\testを作成して下さい。

書き忘れており申し訳ありません。
上記のテスト結果は、実行前に該当フォルダが存在することを確認後(大文字
小文字の表記間違いがないかも確認)に実行した結果です。

プログラム中での削除先指定の文字列を作成する部分はこれでよいのでしょうか?

質問時に書き忘れていましたが、プログラム中での削除先指定の文字列に関
しては、"D:\\\\"と"D:\\"、"test10\\\\"と"test10\\"の両方で確認しています。


...  2009-08-10 09:43:05  No: 70780

エスケープシーケンスで"\"を表す場合は、"\\"でいいです。

一番最初の書き込みのコードで、本当に正しく動作しました?
確か…str.pFromに渡す文字列の最後には、NULLが2つ存在する必要があった筈ですが。。
再度ご確認下さい。


田中  2009-08-10 21:16:27  No: 70781

Resをありがとうございます。

>一番最初の書き込みのコードで、本当に正しく動作しました?

str.pFrom = "D:\\test10\\Test";
で確認しましたが成功しました。
また、
char c1[] = "D:\\test10\\Test";
str.pFrom = c1;
でも成功しました。

>確か…str.pFromに渡す文字列の最後には、NULLが2つ存在する必要があった
筈ですが。。

末尾のCStringの部分を
CString s2 = "Test\0";
CString s2 = "Test\0\0";
と2通り変更しながらそれぞれで

CString s1 = "D:\\"
char c1[100];
lstrcpy(c1, s1);
lstrcat(c1, "test10\\");
lstrcat(c1, s2);

str.pFrom = c1;

として試してみましたが以前と同じエラー表示が出てしまいました。


田中  2009-08-10 21:41:29  No: 70782

申し訳ありません、\0がNULL文字のエスケープシーケンスだと勘違いしてし
まい前記のミスをしてしまいました。
送信後に気づいて以下のテスト確認をしてみましたが、やはりエラー表示が
出ました。

>確か…str.pFromに渡す文字列の最後には、NULLが2つ存在する必要があった筈ですが。。

末尾のCStringの部分を
CString s2 = "Test" + NULL;
CString s2 = "Test" + NULL + NULL;
と2通り変更しながらそれぞれで

CString s1 = "D:\\"
char c1[100];
lstrcpy(c1, s1);
lstrcat(c1, "test10\\");
lstrcat(c1, s2);

str.pFrom = c1;


subaru  2009-08-10 23:26:52  No: 70783

>str.pFrom = "D:\\test10\\Test";
>で確認しましたが成功しました。
>また、
>char c1[] = "D:\\test10\\Test";
>str.pFrom = c1;
>でも成功しました。

これはたまたま動いているだけでしょう。
(UNICODE版だとエラーになるので)

>>確か…str.pFromに渡す文字列の最後には、NULLが2つ存在する必要があった
>筈ですが。。
>
>末尾のCStringの部分を
>CString s2 = "Test\0";
>CString s2 = "Test\0\0";
>と2通り変更しながらそれぞれで
>
>CString s1 = "D:\\"
>char c1[100];
>lstrcpy(c1, s1);
>lstrcat(c1, "test10\\");
>lstrcat(c1, s2);
>
>str.pFrom = c1;
>
>として試してみましたが以前と同じエラー表示が出てしまいました。

CStringもlstrcatも最初の'\0'以降は無視するはず。
配列を0で初期化しておくか
CopyMemoryなどを使って'\0'までコピーした方がいいです。

ちなみにマルチバイト文字セットでコンパイルの場合、
パスを保持する配列のサイズは最低でもMAX_PATH×2必要です。
あと、NULL文字は'\0'のことです。


田中  2009-08-11 04:44:25  No: 70784

subaruさんResをありがとうございます。
…さんとsubaruさんのアドバイスを参考にさせていただき、自分なりに試行
錯誤の結果以下の形で削除に成功できました。
…さん、subaruさん本当にありがとうございました。

CString s1 = "D:\\";
CString s2 = "Test";
Cstring s3 = s1 + "test10\\" + s2;
char* cPointer = new char[s3.GetLength() + 2];
lstrcpy(cPointer, s3);
cPointer[s3.GetLength() + 1] = 0;

srt.pFrom = cPointer;


...  2009-08-11 07:11:14  No: 70785

解決して良かったですね。
# NULL文字と示した方が良かったですね、済みません。。

CStringをせっかく使用しているのなら、この方が簡単じゃない?

CString s1 = "D:\\";
CString s2 = "test10\\";
CString s3 = "Test";
CString tgt.Format("%s%s%s%c", s1, s2, s3, '\0');
 
srt.pFrom = tgt;
  :
  :
以下略


田中  2009-08-12 07:15:26  No: 70786

Resをありがとうございます、おかげさまで何とか成功することが出来ました。
いくつかのサイトで見かけたサンプルコード内ですべて配列が使用されていたため、CStringはpFromの設

定には使えないものと思い込んでいました。
また、MSDNや書籍の読みが浅かったため文字列の終わりはNULL1文字と思い込んでいたこととあわせお二方にお手数をおかけしてしまいました。

進んだコード例をご提示いただいたことにより、さらにシンプルなコードに改良できることに気づかせて

いただき、以下のようなコードでも成功することが出来ました。重ね重ねありがとうございました。

CString s1 = "D:\\";
CString s2 = "Test";
s1 = s1 + "test10\\" + s2 + '\0';

str.pFrom = s1;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加