プロが教えるわが家の防犯対策術!

お世話になってます。

VC++2010、MFCでファイルリストを生成するプログラムを作っています。
(今回質問した部分以外は正常に動作しています)

ファイル生成後、エクスプローラで、生成したリスト(○○.html)を選択状態にしたいです。

しかし、デスクトップ直下に同名のファイル( 例: AlbumList.html )が既にある場合、うまく行きません。


【不具合1】ファイルの生成は意図したディレクトリにされているのに、エクスプローラに「/select」をつけて、開くと、デスクトップ直下の同名のファイル( 例: AlbumList.html )が開かれて(選択されて)しまう


  TRACE(_T("◆FileName→%s \r\n" ),FileName);
  TRACE(_T("◆savePath→%s \r\n" ),savePath);

  //★エクスプローラで開く
  ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,") + FileName , savePath, SW_SHOWNORMAL );


トレース結果:
 ◆FileName→AlbumList.html
 ◆savePath→D:\\Visual Studio 2010 - Data\\Projects\\FileListCreator_Shift-JIS(75)\\Debug\\FileListCreator(LIST)\\


エクスプローラに開かれて、選択状態になったファイル
 C:\ユーザ\[ユーザ名]\デスクトップ\AlbumList.html

更新されたファイル
 D:\Visual Studio 2010 - Data\Projects\FileListCreator_Shift-JIS(75)\Debug\FileListCreator(LIST)\AlbumList.html


【不具合2】デスクトップに
・ FileListCreator.lnk (リンク)(H:\FileListCreator へのリンク)
・ FileListCreator (フォルダ)(デスクトップにおいた FileListCreator.exe が入っているフォルダ)
 (C:\Users\[ユーザ名]\Desktop\FileListCreator)

があり、FileListCreator.exe から 以下のコードを実行するボタンを押すと、リンクの方が開かれてしまう。

※リンクフォルダ名、exe名ともに、「FileListCreator」でかつ両方がデスクトップにおかれている場合に問題が起こる。

  //http://rararahp.cool.ne.jp/vc/vctips/api.htm
  // 実行ファイルのフルパス取得
  TCHAR szPath[_MAX_PATH];
  GetModuleFileName( NULL, szPath, MAX_PATH);

  CString CurDir;

  CurDir = CurrentDirFunc(szPath); //szPathからファイル名を取り除くユーザー関数
  if (CurDir !=_T("")){
    CurDir.Replace(_T("\\"),_T("\\\\"));
  }


  //★エクスプローラで開く
  ShellExecute(NULL, _T("open"), CurDir, NULL, NULL, SW_SHOWNORMAL);

リンクファイル名を
「FileListCreator2.lnk」などと違う名前にすると、実行ファイルのディレクトりが正しく開かれる。


 →【不具合2】の方は、うまく説明できないので、(1)だけでもお教え下さると嬉しいです。

宜しくお願いします。

A 回答 (3件)

連投すみません。


色々複雑なパスで試してみましたが、こちらではどうしても現象を再現できませんでした。
下記の検証コードと、質問者さんのコードで相違があるとすればパスの成形部分だと思います。
そこが分からない以上、これ以上回答のしようがなくなりました。

@念のため~以下で試されているコードは、"の数に問題ありませんでした。早とちりですみません。


・ファイルが下記のパスにあった場合、ファイルが選択された状態でディレクトリが開かれる。
・ファイルが下記のパスになかった場合、ドキュメントフォルダが開かれる。(デスクトップは見に行かない)
---------------------------------------------------
CString FileName;
CString savePath;

FileName = "vbdebugui.dll";
savePath = "C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\Common7\\IDE\\Remote Debugger\\x86\\1041\\";

ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,") + savePath + FileName, NULL, SW_SHOWNORMAL );
---------------------------------------------------

この回答への補足

CString FileName;
CString savePath = _T("");

型は、上記です。わざわざ、検証までして頂いていたとは、感謝します!

私は、Webページを参考に、引き数の順序を変えてみたり、_T("explore")にしてみたり、と
トライ&エラーで、時間だけが過ぎる感じでした。

OSを書き忘れていましたが、トライ&エラーしていたのは、Vistaで、
今朝、回答者様の返信をみて、もしやと思って、7でも試してみました。

7では、検証まではしていませんが、EXEをダウンロードフォルダにコピーして、
AlbumList.htmlをデスクトップに作って、同じ作業をしたところ、再現(私にとって残念ですがυ)できてしまいました。(私の元のコードでです。)

もうちょっと、回答者さんのコードも含め、試してみます。
それと私の日本語が分かりにくくてすみません。

一応、その他の部分で使っている主な命令文を(コードを)記しておきます。


void CFileListCreatorDlg::ExportFileList(BOOL AutoSaveFLG){
  _wsetlocale(LC_ALL, _T("jpn"));
  ・・・


CurrentDirectory_FLG = FALSE;//←マイドキュメントなどに保存する場合、FALSEとセット

  if (AutoSaveFLG == FALSE) {
    int myResult;

    myResult = MessageBox(_T("当アプリケーションがあるディレクトリにリストを出力しますか?"),_T("出力先"),MB_YESNOCANCEL);
    if(myResult==IDYES){
      CurrentDirectory_FLG = TRUE;//アプリケーションがあるフォルダに出力の場合、TRUE
    }else if(myResult==IDCANCEL){
      return;
    }
  }

CString FileName;


  if (AutoSaveFLG == FALSE) {
    //モーダル
    InputBoxDlg m_dlg;

    //"ファイルに名前をつけて下さい。"

    if (m_dlg.DoModal()==IDOK){
      FileName = _T("");
      FileName = m_dlg.ExportFileName;
    }else{
      FileName = _T("");
    }

    FileName = ProhibitFileName(FileName, FALSE);//ファイル名に使用できない文字を「_」に変えるユーザー関数

    if(FileName == _T("")){
      //エラー表示
      return;
    }else{
      FileName = FileName + _T(".html");
    }
  }

~htmlデータの中身生成~

  // 実行ファイルのフルパス取得
  TCHAR szPath[_MAX_PATH];
  GetModuleFileName( NULL, szPath, MAX_PATH);

・・・

  CString CurDir;
  CurDir = szPath;

  CurDir = CurrentDirFunc(CurDir,TRUE);//EXEのパスからフォルダまでを取るユーザー関数(単にTrimしているだけです。。。)

  if (CurDir !=_T("")){
    CurDir.Replace(_T("\\"),_T("\\\\"));
  }
  if(CurrentDirectory_FLG == FALSE && AutoSaveFLG == FALSE) {
    savePath = WindowsFolder_Func() + _T("\\\\") + _T("FileListCreator(LIST)") + _T("\\\\"); //マイドキュメントなどに保存する場合、WindowsFolder_Func()で求める(ユーザー関数)//こちらで指定しているからマイドキュメントで開くという意味ではないです else の方がメインでトライ&エラーは、主にelseでしています。
  }else{
    if (AutoSaveFLG == TRUE) {
      //FileName = _T("AutoSave");
      savePath = CurDir + _T("\\\\") + _T("FileListCreator(Pref)") + _T("\\\\");
    }else{
      savePath = CurDir + _T("\\\\") + _T("FileListCreator(LIST)") + _T("\\\\");
    }
  }

  if(CreateDirectory(savePath,NULL)){ //一階層下のフォルダにしか作れないが問題なし

  }else{
      
  }

~htmlファイルとtxtファイルを出力処理~ //AlbumList.txtも出力していますが、出力部分コメント化してみても不具合は変わりませんでした。

  _wsetlocale(LC_ALL, _T(""));


  if (AutoSaveFLG == FALSE) {
    TRACE(_T("◆FileName→%s \r\n" ),FileName);
    TRACE(_T("◆savePath→%s \r\n" ),savePath);

    //http://oshiete.goo.ne.jp/qa/2193377.html
    // SetCurrentDirectory(savePath);

    //ShellExecute(handle, "find", path_to_folder, NULL, NULL, 0);

    ////★エクスプローラで開く(元のソース)
    //ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,") + FileName , savePath, SW_SHOWNORMAL );

    ////★エクスプローラで開く(回答者様のソース)
    ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,") + savePath + FileName, NULL, SW_SHOWNORMAL );

    ////★エクスプローラで開く(念のため、""で囲った部分)
    //CString strArgs;
    //strArgs = _T("/select, \"");
    //strArgs +=savePath + FileName;
    //strArgs += _T("\"");

    //ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), strArgs, NULL, SW_SHOWNORMAL );

    //◆handle
    //m_hWnd
    //::GetActiveWindow()
  }
}

長々とすみません、VC++は初めてなので、どこに問題あるか・・・という感じです。
もう少し考えてみます。

補足日時:2012/03/29 11:19
    • good
    • 0
この回答へのお礼

出来ました!!フォローありがとうございました。

【不具合1】

【誤】//★エクスプローラで開く(元のソース)
 ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,") + FileName , savePath, SW_SHOWNORMAL );

【正】SetCurrentDirectory(savePath); //←不要かもしれないですが・・・
  //★エクスプローラで開く
  ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,.\\" + FileName) , savePath, SW_SHOWNORMAL );


【不具合2】

【誤】//★エクスプローラで開く
  ShellExecute(NULL, _T("open"), CurDir, NULL, NULL, SW_SHOWNORMAL);

【正】SetCurrentDirectory(CurDir); //←不要かもしれないですが・・・
  //★エクスプローラで開く
  ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T(".\\") , NULL, SW_SHOWNORMAL );

自分のソースばかり採用して、頑固ですみませんでした。多分、定石では内容な気がしますがυ

問題が無ければ明日の15時ごろ、締め切ります。ありがとうございました!

お礼日時:2012/03/29 19:59

私が昨日検証したとき、ファイルがなかったり、パスが間違っていたりすると、


ログインユーザーのドキュメントフォルダが開きました。
なのでこれは、そういう仕様なのでしょう。

気になるのは、文字連結をすると上記のようになる(=パスの生成に失敗している?)ということです。
一応、FileNameとsavePathの型を教えてください。

念のため~以下で試されているコードは、常に失敗するのではないでしょうか?
最後の「strArgs += _T("\"");」で、"の数が合わなくなると思います。

>> ただ、デウストップにある「AlbumList.html」の名前を変えて、「AlbumList002.html」などと別名にする場合、
>> 私のコードではうまく行きますが、教えて頂いたコードではドキュメントフォルダが開きます。
そうなると、「フォルダを含めたパスを渡した時は、デスクトップは見にいかない」仕様のようですね。

もう少し検証してみます。
    • good
    • 0
この回答へのお礼

問題箇所の切り分け、ご回答 有難うございました!

回答No.3のお礼欄にて、【不具合1】【不具合2】の解消法を載せました。
補足の所は、関係ないです、見にくくてすみません。

では、締め切ります。

お礼日時:2012/03/30 17:16

不具合2の方はちょっと良く分からなかったのですが、多分1と同様の問題であると思います。



今回の場合は、ShellExecuteの引数として、
EXPLORER.EXEへのパラメータが「_T("/select,") + FileName」、
EXPLORER.EXEの作業ディレクトリが「savePath」
として指定されています。

この作業ディレクトリは、"EXPLORER.EXEというタスクが動作するにあたっての既定値"となるフォルダであり、
"EXPLORER.EXEが開くファイルがあるフォルダ"ではありません。
「ファイル検索場所の参考にはするかもしれないけど、本来は目的がまったく異なる物」です。

その点を踏まえて、あくまで仮説なのですが、
「EXPLORER.EXEはまず色々(デスクトップetc)探しに行って、パラメータで指定されたファイルがなければ、最後に作業ディレクトリを見に行く」
という仕様なのではないでしょうか。

で、解決方法なのですが、下記のコードでいけると思います。
ファイル名だけでなく、フォルダを含めたパス全体を渡しています。
ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), _T("/select,") + savePath + FileName , NULL, SW_SHOWNORMAL );

この回答への補足

ご回答ありがとうございます。返信が遅くなってしまって、すみません。

>「EXPLORER.EXEはまず色々(デスクトップetc)探しに行って、パラメータで指定されたファイルがなければ、最後に作業ディレクトリを見に行く」
という仕様なのでは・・・

私もその可能性があると思い始めてました。でも今回教えられた事も何度か試しましたが、うまくいきませんでした。でも、どこかにミスがあるといけないので、教えて頂いたソースをコピペして、実行しました。

どうなったかと言うと、
ドキュメントフォルダ(C:\Users\[ユーザー名]\Documents)が選択されました。

 デレクトリ 「C:\Users\[ユーザー名]\」 が開かれ、ドキュメントフォルダ「Documents」が選択されています。)

 ちなみに、AlbumList.htmlはドキュメントフォルダにもあります。ファイルではなくフォルダが選択状態になっています。


念のため、次に以下のコードでも実行してみましたが、結果は同じでした。

  CString strArgs;
  strArgs = _T("/select,\"");
  strArgs +=savePath + FileName;
  strArgs += _T("\"");

  ShellExecute( NULL, _T("open"), _T("C:\\WINDOWS\\EXPLORER.EXE"), strArgs , NULL, SW_SHOWNORMAL );

  //ドキュメントフォルダ(C:\Users\[ユーザー名]\Documents)に飛んだ


▼これは知りませんでした、試行錯誤しているうちにそうなってしまいました▼

この作業ディレクトリは、"EXPLORER.EXEというタスクが動作するにあたっての既定値"となるフォルダであり、
"EXPLORER.EXEが開くファイルがあるフォルダ"ではありません。
「ファイル検索場所の参考にはするかもしれないけど、本来は目的がまったく異なる物」です。

▲今後の参考にしたいです▲

補足日時:2012/03/29 00:07
    • good
    • 0
この回答へのお礼

お礼の欄に申し訳ありません。

やはり、私が書いた元のコードでも、教えて頂いたコードで、デスクトップやドキュメント フォルダが開くだけです。

なにか、私のPC固有の問題な気がしてきました。

もしや[ユーザ名]に . (ドット) を含んでいるから駄目なのでしょうか?
ただ、デウストップにある「AlbumList.html」の名前を変えて、「AlbumList002.html」などと別名にする場合、私のコードではうまく行きますが、教えて頂いたコードではドキュメントフォルダが開きます。

savePathという変数名通り、最初は、私もパスを指定してました。今は、saveFolder とか、saveDirなどの意味で使っています。試行錯誤を重ねた結果、私のコードになりました。

http://msdn.microsoft.com/ja-jp/library/cc422072 …

上のWebページなども参考にしているのですが、困りました。。。フォルダを開くだけなら、簡単なのですが、選択状態にするのが、難しいです。

お礼日時:2012/03/29 05:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!