ショッピングモール  


【掲示板ご利用上の注意】

 ※題名は具体的に!
 ※学校の課題の丸投げ禁止!
 ※ソースの添付は「HTML変換ツール」で字下げ!
 ※返信の引用は最小限に!
 ※環境(OSとコンパイラ)や症状は具体的に詳しく!
 ※マルチポスト(多重投稿)は謹んで!

 詳しくはこちら



 本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール   掲示板1こちら


管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧

No.3147

カレントディレクトリの変更
投稿者---kolona(2004/12/04 19:20:59)



私はコマンドライン引数からファイル名を取得し、そのファイルに変更を加えた後".txt"を余分に付け加えた
別ファイルに変更されたデータを書き込むプログラムを作っています。
実行ファイルにファイルをドロップするとそのファイルを開いて処理します。
あらかた完成したのですが、書き込むファイルと同名のファイルがあったときに、
別のファイル名を取得したときだけ全く関係ないディレクトリにファイルが作られてしまう不具合があります。
ディレクトリは大体
C:\Program Files\Common Files\System\Mapi\1041\NT
C:\Documents and Settings\ユーザー名
のどちらかになるようです。
そのまま上書きを選択すれば元ファイルと同じディレクトリに作られるのに、
ファイル名を取得した後このような場所にファイルが飛んでしまうということは、
フルパスのファイル名が処理された後に限りフルパスで処理し、
ファイル名のみを取得した場合は、あらかじめ設定されたカレントディレクトリのパスを補完して処理していると考えていま

す。
カレントディレクトリを書き換える関数は見つけたのですが、なぜこのソースで
C:\Program Files\Common Files\System\Mapi\1041\NT
がカレントになるのかさっぱりわかりませんでした。
("カレントディレクトリを取得 C言語" "カレントディレクトリ C言語"等のキーワードでネットで調べても )
しかもどっちになるのかはどうもランダムで一定していないようなのです。

内部でどのような処理が行なわれてランダムな結果に至るのか、SetCurrentDirectory();はどこのパラメータを書き換えてい

るのか、
といったことが現在の疑問です。
どなたか教えて頂ければ幸いです
環境は
WinXP-Pro
コンパイラは
borland c++ compiler 5.5
です

問題のソースは以下に示します。
関数int currentd(char *sp2,char *sp1,int max)はファイルのパスを切り出すための関数です。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <windows.h>

int argcv(int ac,char **av,char *cp,int maxhai,int max);
int currentd(char *sp2,char *sp1,int max);

int main(int argc, char **argv){

FILE *f1,*f2;
int y,x;
char fm1[256],fm2[256],e[4]={0},d[]=".txt";
char par[3][255];//コマンドライン引数を保持する


x=0;
y=argcv(argc,argv,&(par[0][0]),255,3);
if(y>=2){//もしコマンドライン引数の*argv[]から2つ以上の文字列がコピーできたなら
  strcpy(fm1,&par[1][0]);//2つ目の文字列をファイル名としてセット
  if((f1=fopen(fm1,"r"))==NULL){
    printf("ファイルを開けません\n");
  }
  else{x=1;}
}


while(x==0){
  printf("開くファイル名を入力してください\n");
  gets(fm1);
  if((f1=fopen(fm1,"r"))==NULL){
    printf("ファイルを開けません\n");
  }
  else{x=1;}
}

strcpy(fm2,fm1);
strcat(fm2,d);
e[0]=0;
//SetCurrentDirectory("c:");
while(e[0]!='1'){
  if((f2=fopen(fm2,"r"))==NULL){
    f2=fopen(fm2,"wb");
    e[0]='1';e[1]='\0';
  }
  else{
    puts("上書きになります");
    puts(" 1  開く  2  やっぱりやめる  3  別のファイル名で開く");
    gets(e);
    if(e[0]=='1'){
      f2=fopen(fm2,"w");
      e[0]='1';e[1]='\0';
    }
    if(e[0]=='2'){exit(1);}
    if(e[0]=='3'){
      puts("ファイル名は?");
      gets(fm2);
      if((f2=fopen(fm2,"r"))==NULL){
        f2=fopen(fm2,"wb");
        e[0]='1';e[1]='\0';
      }
    }
  }
}

printf("処理中\n");
fprintf(f2,"処理データ書き込み");

fclose(f2);
fclose(f1);
gets(fm1);
return 0;
}
/*********************************************************************/
/*
  コマンドライン引数を指定のchar配列*cpに代入する
  代入する最大要素数はmax
  一度に代入する最大サイズはmaxhai
  char str[3][255];
  と宣言したなら
  y=argcv(argc,argv,&(str[0][0]),255,3);
  のように使う
*/
int argcv(int ac,char **av,char *cp,int maxhai,int max){

if(max>ac){max=ac;}
ac=max;
while(max--){
  strncpy(cp,*av,maxhai);
  cp=cp+maxhai;
  av=av++;
}
printf("return %d\n",ac);
return ac;
}
/*
  sp1のファイル名と同じディレクトリパスを
  sp2にセットする
  maxバイトまで有効
*/

int currentd(char *sp2,char *sp1,int max){

int x;

x=0;
while(sp1[x]){//sp1の文字列終端まで移動
  x++;
}
while(sp1[x]!='\\'){//sp1の最後の\まで移動
  x--;
}
x++;
if(x+1>max){return 0;}//sp2の最大文字数を超えるので何もしない
sp2[x]=0;x--;
while(x>=0){//\文字より前を全てコピーする
  sp2[x]=sp1[x];
  x--;
}
return 1;
}





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:カレントディレクトリの変更 3148 KING・王 2004/12/04 22:17:15


No.3148

Re:カレントディレクトリの変更
投稿者---KING・王(2004/12/04 22:17:15)



>内部でどのような処理が行なわれてランダムな結果に至るのか、SetCurrentDirectory();はどこのパラメータを書き換えてい
>るのか、

MSDNのSetCurrentDirectory()より
> 現在のプロセスのカレントディレクトリを設定します。
となっています。

    if(e[0]=='3'){
      puts("ファイル名は?");
      gets(fm2);
      if((f2=fopen(fm2,"r"))==NULL){
        f2=fopen(fm2,"wb");
        e[0]='1';e[1]='\0';
      }
    }


掲載されているプログラムは省略部分があると思いますが、
この部分の直前で、SetCurrentDirectory()でパスを設定しても、
そのパスに出力されませんか?



この投稿にコメントする

削除パスワード

No.3149

Re:カレントディレクトリの変更
投稿者---kolona(2004/12/04 23:05:38)


>掲載されているプログラムは省略部分があると思いますが、
>この部分の直前で、SetCurrentDirectory()でパスを設定しても、
>そのパスに出力されませんか?

言葉足らずでした。すいません。
2つ目のwhile(){}の直前で
SetCurrentDirectory("c:\\");
とすればcドライブのルートに出力されることを確認しました。
セットする方法はわかるんですが、こちらが明示的にSetCurrentDirectoryを呼び出していないにもかかわらず(windowsによって?)カレントが2通りに書き換わっている仕組みが知りたいのです。



この投稿にコメントする

削除パスワード

No.3152

Re:カレントディレクトリの変更
投稿者---RAPT(2004/12/05 05:08:42)


とりあえず、どこで値が書き換わっているか調べてみては?
GetCurrentDirectory()で取得できます。

それから、ファイルパス処理は、Windows APIが使用できるのであれば、
shlwapiのPathRemoveFileSpec(), PathAppend() あたりを使うと楽かも。



この投稿にコメントする

削除パスワード

No.3158

Re:カレントディレクトリの変更
投稿者---kolona(2004/12/05 15:42:57)


>とりあえず、どこで値が書き換わっているか調べてみては?
GetCurrentDirectory()で取得できます。

参考にしたHPに有ったのに、気づきませんでした。
調べてみたところ,ファイル名がコマンドライン引数できたときはカレントが既に書き換わっていることがわかりました。念のためコマンドプロンプトから引数を与えたところ,明示的にSetCurrentDirectoryを呼び出さない限りカレントに変更は有りませんでした。どうやらwindowsの方で何かやっているようですが,レジストリ設定なのか,OSの仕様なのかわかりませんでした。

>それから、ファイルパス処理は、Windows APIが使用できるのであれば、
>shlwapiのPathRemoveFileSpec(), PathAppend() あたりを使うと楽かも。

以下の行を追加すればfm2にファイル名がセットされると思い,コンパイルしてみましたが,winmainでないと外部シンボル未解決のエラーが出ますので、
同じ関数名の大体同じ動作をする代替関数を自作してコンパイルしました。結果、期待通りの動作をしてくれました。
パクリのPathRemoveFileSpecを使えばSetCurrentDirectory用のパスが作成できるので、解決しました。

KING・王さん、RAPTさん、どうもありがとうございました。
strcpy(fm2,fm1);
p=PathFindFileName(fm1);
printf("fileName1=%s\n",p);
PathRemoveFileSpec(fm2);
PathAppend(fm2,p);
以下に関数を表示します。


/** win32 APIのパクリ */
char* PathFindFileName(char *sp){

int x,y;

x=0;
y=0;
while(sp[x]){
  if(sp[x]=='\\'){y=x;}
  x++;
}

return &sp[y+1];
}

int PathRemoveFileSpec(char *sp){

int x,y;

x=0;
y=0;
while(sp[x]){
  if(sp[x]=='\\'){y=x;}
  x++;
}

if(y!=0){
  if(sp[y-1]=='\\'){sp[y-1]=0;}
  else{sp[y]=0;}
  y=1;
}

return y;
}

int PathAppend(char *sp1,char *fnamepath){

while(*sp1){sp1++;}
while(*fnamepath=='\\'){fnamepath++;}//ファイル名先頭の\は読み飛ばす

if(*(--sp1)=='\\'){strcat(sp1,fnamepath);}
else{strcat(sp1,"\\");strcat(sp1,fnamepath);}

return 1;
}



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    記事検索    ログ    タグ一覧




掲示板提供:Real Integrity