アプリ版:「スタンプのみでお礼する」機能のリリースについて

現在コマンドライン引数を利用した、Drag&Dropで入力されたバイナリファイルをテキストファイルに出力するプログラムをCで作成しています。

その過程で、Drag&Dropされたファイル以外にもテキストファイル(option.txt)を読み込みたいのですが、どうしてもそのファイルをオープンすることができません。

次は問題の部分だけを抜き出したソースです。

#include <stdio.h>
int main(int argc,char *argv[])
{
 FILE *s;
 s=fopen("option.txt","r");
 if( !s ){
  printf("Error: cannot open file(option.txt)\n");
 }
  else printf("OK!\n");

 if(argc == 2) printf("%s\n",argv[1]);
 else if(argc ==1) printf("No Drag&Drop File\n");

 return 0;
}

Drag&Dropしない時(作成された実行ファイルをダブルクリックで起動する時)は
 OK!
 No Drag&Drop File
となり、問題のoption.txtのファイルは開けているのですが、適当なバイナリファイル(7.chn)をDrag&Dropすると
 Error: cannot open file(option.txt)
 C:\Documents and Settings\[ユーザー名]\デスクトップ\Program\7.chn
と、先ほどまで開けていたoption.txtのテキストファイルが急に開けなくなってしまいました。

どうにも原因・解決策が分かりませんでしたので、お聞きしたくこちらに書き込みをさせてもらいました。

どなたか分かる方いらっしゃいましたらよろしくお願いします。

A 回答 (15件中1~10件)

#11回答者です。



>よって、argv[0]でフルパスが取れるか否かは処理系次第です。
#7の回答・補足から処理系は判明しています。

WindowsXP
Borland C++ Compiler 5.5

同じ環境で動作確認しましたので、問題ないと思いますが、違うバージョンのWindowsで動かす予定があれば念のため動作確認した方が良いかも知れませんね。


ついでに、とことん手抜きのプログラム書くと・・・
実行ファイルのファイル名の長さは決まっていると思うので、こんな感じで。

#include <stdio.h>
#include <string.h>
#define EXEFILE_LEN 7 //実行ファイルのファイル名の長さ
void main(int argc,char *argv[])
{
char str[1024]; //エラー処理してないので多めに
strcpy(str,argv[0]);
str[strlen(argv[0])-EXEFILE_LEN] = '\0'; //ファイル名の前で切る
strcat(str,"option.txt");
puts(str);
{char c = getchar();}
}

この回答への補足

そうですね、大学のPCにWindows98がひとつありますのでそれでの動作確認だけはしたいと思います。

こういう'\0'を挿入する方法は思いつきませんでしたね。
確認しましたが、こちらでも正常にフルパスが取得できました。

ちなみに、私の考えたプログラムはこのような感じです

#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[])
{
char m[200]="";
char*j=strrchr(argv[0],'\\'); //後ろから最初の\を検索
int k=j-argv[0]+1;
strncpy(m,argv[0],k);
strcat(m,"option.txt");
printf("Path : %s\n",m);
fflush(stdin);
getchar();
}

補足日時:2006/12/16 21:29
    • good
    • 0

# 自分用(?)の簡単なツールのようなので蛇足かも知れませんが。



> char*j=strrchr(argv[0],'\\'); //後ろから最初の\を検索

この処理では、実行ファイル名に特定の漢字が入ると意図しない動作になりますね。

# わざわざ自作しなくても、パスだけ取るのは_splitpathで、合成は_makepathで可能だと思うのですが。
# (実際の関数名は、_splitpathのように先頭にアンダスコアがつきます)

この回答への補足

そういう問題があるのですか、知りませんでした。

特にファイル名には漢字等は使用しないので大丈夫かとは思われますが、_splitpathを用いたoption.txtのフルパスを取得する関数も別に自作してありますので、何か不都合があればこちらに切り替えることにしますね。

補足日時:2006/12/16 23:13
    • good
    • 0
この回答へのお礼

今まで教えていただいたことを参考に、一応プログラムが完成しました。
期待通りの出力が得られましたので、ひとまずこれでよしとしたいと思います。

これまで教えてくださった方々ありがとうございました。

お礼日時:2006/12/16 23:48

凄いなぁ、ユーザが実行ファイルのファイル名を変えると動かなくなるプログラムですか。


あー、エクスプローラ上で、同じフォルダ内でコピペしただけでも動かなくなるんですね?
いや、凄いなぁ。「専門家」にはできない芸当ですね。

あ、念のために補足しておきますと、argv[0]にフルパスが入るか否かはOS依存じゃなくて処理系依存ですから。
つまり、BCCではなく他のコンパイラにすると使えなくなる(かもしれない)手法ってことです。
この件に関しては私も専門家ではないのでVCではどうなるか知りませんが、
少なくともgccでは巧くいかないことは判っています。

この回答への補足

>凄いなぁ、ユーザが実行ファイルのファイル名を変えると動かなくなる>プログラムですか。
>あー、エクスプローラ上で、同じフォルダ内でコピペしただけでも動か>なくなるんですね?
>いや、凄いなぁ。「専門家」にはできない芸当ですね。
???

>BCCではなく他のコンパイラにすると使えなくなる(かもしれない)手法っ>てことです。
なるほど、Windows98でもbccなら同様に動作するということですね。
それの確認も含めて、今度動作確認してみることにします。

補足日時:2006/12/16 23:26
    • good
    • 0

念のための補足です。



C/C++の言語仕様では、argv[0]は「呼ばれたプログラム名」か「空文字("")」のいずれかが入ることになっており、
(まぁ現実にはPCで空文字って事は通常ないですが)
空でない場合も、ここでいうプログラムが絶対パスなのか、ユーザの入力文字列そのままなのか、
ファイル名だけなのか、等については規定されていません。

よって、argv[0]でフルパスが取れるか否かは処理系次第です。
# 入力文字がそのまま取れる奴とかもあります。

この回答への補足

argv[0]は処理系に左右されるのですね。

このプログラムは大学での実験データの解析に用いますので、大学のPCで使用できればそのまま使いたいと思います。
もし、不具合が起きるようならGetModuleFileNameの方を用いることにします。

補足ありがとうございました。

補足日時:2006/12/16 20:46
    • good
    • 0

#include <stdio.h>


void main(int argc,char *argv[])
{
char c;
puts(argv[0]);
c = getchar();
}

実行ファイルのパスは argv[0] を見れば分かると思いますよ。

この回答への補足

argv[0]でパスは確認できたのですね。

そちらを用いて、最後の実行ファイル名を削除し、"option.txt"を追加する方法でoption.txtのフルパスを取得することができました。

ちなみに、先ほど教えていただいたGetModuleFileNameとsplitpathを使う方法でもフルパスを指定するのに成功しました。

しかし、argv[0]の方がシンプルなコードで表現できましたので、前者の方を採用したいと思います。

これで、思い通りのプログラムを組むことができそうです。

ご教授いただきありがとうございました。

補足日時:2006/12/16 20:28
    • good
    • 0

ちなみに、makepathってのもあるので、実行ファイルのパスが取れれば、


そこからoption.txtの絶対パスを作るのもできるでしょう。
    • good
    • 0

失礼、ファイルオープンだけが目的なら最後のディレクトリ移動は不要ですね。


splitpathまでできれば十分。

この回答への補足

なるほど、少し調べてみましたら、splitpathでディレクトリ、ドライブ、ファイル名、拡張子別に文字列を切り分けるのですね。

わかりました、参考にしながらプログラムを組んでみようと思います。

どうもありがとうございました!

補足日時:2006/12/16 18:19
    • good
    • 0

"C:\Documents and Settings\[ユーザー名]"



ここだとすると、「止まっている」というより「ユーザのルート」かも。
直接D&Dしてるので、パスがそこになってるとか。

ためしに、デスクトップなどのユーザ配下ではないディレクトリに全ファイルを置いてD&Dするとどうなりますか。
それでも上記ディレクトリになるなら、止まっているわけではないことになるかと思います。

# GetModuleFileNameだと実行ファイルの絶対パスが取れるので、
# option.txtという名前からすると、上記をsplitpath等して、
# SetCurrentDirectoryとかする方がいいのかもしれませんが。

この回答への補足

ご指摘通り、"C:\"や"..\デスクトップ"など、いろいろなところで試してみましたが、すべてカレントは
"C:\Documents and Settings\[ユーザー名]"
となっていました。

ですので、MrBanさんのおっしゃるとおり「止まって」はいないようですね。

相対パスは無理そうなので諦めることにして、絶対パスの取得がGetModuleFileNameでできるということですので、勉強してこれから試してみることにします。

補足日時:2006/12/16 18:07
    • good
    • 0

WindowsXP


Borland C++ Compiler 5.5

上記の環境で確認しましたが、Drag&Dropで起動すると、

C:\Documents and Settings\[ユーザー名]\

プログラムのパスにも、Drag元のパスにも関係なく、常に上記がカレントディレクトリでした。

きっとcmd.exeのデフォルト設定でしょう。

この回答への補足

私の環境も全く同じなので、何かこちらのバグというわけではないようですね。

仕方がありませんので、相対パスは諦めてフルパスでoption.txtを指定するようにします。

調べていただいて、どうもありがとうございました。

補足日時:2006/12/16 17:58
    • good
    • 0

#include <stdio.h>


#include <windows.h>
void main(void)
{
char s[255];
char c;
GetCurrentDirectory(255,s);
printf("%s\n", s);
c = getchar();
}

こんな感じで、実行時のカレントディレクトリを確認すればすっきりするかも。

この回答への補足

カレントディレクトリを調べるコマンドがあったのですね。

試してみましたところ、
"C:\Documents and Settings\[ユーザー名]"
で止まっていました。

Drag元もDrop先もoption.txtも実行ファイルのある
"C:\Documents and Settings\[ユーザー名]\デスクトップ\Program"
に存在するので、このディレクトリがカレントになっているのが疑問です。

補足日時:2006/12/16 17:47
    • good
    • 0

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