Navigation Log - なびろぐ -
2006/01/23

...X680x0 spirit inside...

この日記はGNSで生成しています。
この日記の画像はOPTPiX webDesigner Ver.4で生成しています。

hauN
Go amazon.co.jp

■ご注文リストから■ [一覧]
■Amazonギフト券■ [購入]
ゆゆ式 8巻 []
ゆゆ式 8巻
Amazonほしい物リスト


2006/01/23 (月) 晴時々曇

GetOpenFileName() (PC, プログラム)

_ GetOpenFileName()

  • nFileExtensionが0かどうかで判定するのは正しくない。MSDN - OPENFILENAME Structureによると、nFileExtensionの項に「If the user typed "." as the last character in the file name, this member specifies zero.」・・・つまり、複数選択でなくても0で返るケースがあるということで。
  • OFN_ALLOWMULTISELECTが指定されているとき、選択ファイルが1つのときは"path\0\0"、2つ以上のときは"dir\0file1\0file2\0...fileN\0\0"が返るので、それで判定する。
  • ディレクトリ名の格納には、「末尾の"\"が付いている」ことを規定、つまりPathRemoveBackslash()よりPathAddBackslash()のほうがルールが一本化されて安全。*1

*1: フォルダ"c:\hoge\"にフォルダ"01"と実行ファイル"01.exe"があるとき、"c:\hoge\01"というパスがフォルダでなく実行ファイルを指してしまうケースがある。これを回避するためにも、「ディレクトリ名には"\"を付けて格納する」ほうが安全。

_ ということで、手許のソースから貼り付けてみる。


#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <shlwapi.h>

int myGetOpenFileNameMulti(
  TCHAR *startpath,
  TCHAR ***ret_pathlist,
  int *ret_npathlist
) {
    OPENFILENAME ofn;
    TCHAR dir[MAX_PATH];
    TCHAR *p;
    TCHAR *file;
    TCHAR path[MAX_PATH*256];
    TCHAR **pathlist;
    TCHAR **newpathlist;
    int pathlistsize;
    int npathlist;
    int i;
    int dirlen;
    int filelen;

    // 初期化
    pathlistsize = 16;
    pathlist = (TCHAR **)GlobalAlloc(
      GPTR, pathlistsize*sizeof(TCHAR *)
    );
    if ( pathlist == NULL ) {
        return (-1);
    }
    npathlist = 0;
    *(ret_pathlist) = NULL;
    *(ret_npathlist) = npathlist;

    // API発行
    lstrcpyn( path, startpath, sizeof(path) );
    lstrcpyn( dir, startpath, sizeof(dir) );
    PathRemoveFileSpec( dir );
    PathAddBackslash( dir );
    if ( !lstrcmpi( path, dir ) ) {
        lstrcpyn( path, "", sizeof(path) );
    }
    ZeroMemory( &ofn, sizeof(ofn) );
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.lpstrFilter = "すべてのファイル (*.*)\0*.*\0";
    ofn.lpstrFile = path;
    ofn.lpstrInitialDir = dir;
    ofn.nMaxFile = sizeof(path);
    ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
                OFN_EXPLORER | OFN_ALLOWMULTISELECT;
    if ( GetOpenFileName( &ofn ) == FALSE ) {
        GlobalFree( pathlist );
        return (0);
    }

    // 単一ファイル選択ならすぐ終了
    if ( ( !(ofn.Flags & OFN_ALLOWMULTISELECT) ) ||
         ( path[ lstrlen( path )+1 ] == '\0' ) ) {
        p = (TCHAR *)GlobalAlloc( GPTR, lstrlen( path )+1 );
        if ( p == NULL ) {
            goto err_allocpath;
        }
        lstrcpy( p, path );
        pathlist[npathlist++] = p;
        goto ret_ok;
    }

    // 複数ファイルのpathを展開しながらストア
    lstrcpyn( dir, path, sizeof(dir) );
    PathAddBackslash( dir );
    dirlen = lstrlen( dir );
    file = path+lstrlen( path )+1;
    while ( file[0] ) {
        filelen = lstrlen( file );
        p = (TCHAR *)GlobalAlloc( GPTR, dirlen+filelen+1 );
        if ( p == NULL ) {
            goto err_allocpath;
        }
        while ( npathlist >= pathlistsize ) {
            pathlistsize *= 2;
            newpathlist = (TCHAR **)GlobalReAlloc(
              pathlist, pathlistsize*sizeof(TCHAR *), 
              GMEM_MOVEABLE|GMEM_ZEROINIT
            );
            if ( newpathlist == NULL ) {
                goto err_allocpath;
            }
            pathlist = newpathlist;
        }
        PathCombine( p, dir, file );
        pathlist[npathlist++] = p;
        file += filelen+1;
    }
    goto ret_ok;

  ret_ok:;
    *(ret_pathlist) = pathlist;
    *(ret_npathlist) = npathlist;
    return (npathlist);

  err_allocpath:;
    for ( i=0; i<npathlist; i++ ) {
        GlobalFree( pathlist[i] );
    }
    GlobalFree( pathlist );
    return (-1);
}


int main(
  int argc,
  char *argv[]
) {
    TCHAR **pathlist;
    int npathlist;
    int ret;
    int i;

    if( argc == 1 ) {
        printf( "usage: %s [startpath]\n", argv[0] );
        exit( EXIT_SUCCESS );
    }

    ret = myGetOpenFileNameMulti(
      argv[argc-1], &pathlist, &npathlist
    );
    if ( ret < 0 ) {
        printf( "error.\n" );
        exit( EXIT_SUCCESS );
    }
    if ( ret == 0 ) {
        printf( "no file selected.\n" );
        exit( EXIT_SUCCESS );
    }

    for ( i=0; i<npathlist; i++ ) {
        printf( "%d: %s\n", i, pathlist[i] );
        GlobalFree( pathlist[i] );
    }
    GlobalFree( pathlist );
    return( EXIT_SUCCESS );
}

// [EOF]

_ 追記。「!(ofn.Flags & OFN_ALLOWMULTISELECT)」の"&"がダブっていた。感謝

_ もともとこのコード、このまま使うだけならofn.Flagsの値なんぞチェックしなくていい。コピペ&修正でこのコードを使いまわすとき、上のOFN_ALLOWMULTISELECTを外してしまった場合の対策で、今回ここに書くために追記したもの。それでミスってちゃ世話ない・・・(苦笑)。





メールはこちらへ...[後藤浩昭 / Hiroaki GOTO / GORRY / gorry@hauN.org]

「表紙へ戻る」
「会議室」 「最新版」 「なびろぐindex」 「GNSソースを読む」