2016-11-27 10 views
1

OPENFILENAMEダイアログからファイルパスを取得する関数を作成しようとしています。私のコードはこのように見えます。 OPENFILENAMEダイアログは、ファイルパスの代わりにアジアの文字を返します

wstring src; 

bool open() 
{ 
    const string title = "Select a File"; 

    wchar_t filename[MAX_PATH]; 

    OPENFILENAMEA ofn; 
    ZeroMemory(&filename, sizeof(filename)); 
    ZeroMemory(&ofn, sizeof(ofn)); 

    ofn.lStructSize  = sizeof(ofn); 
    ofn.hwndOwner  = NULL; 
    ofn.lpstrFilter  = "Music (.mp3)\0*.mp3\0All\0*.*\0"; 
    ofn.lpstrFile  = LPSTR(filename); 
    ofn.nMaxFile  = MAX_PATH; 
    ofn.lpstrTitle  = title.c_str(); 
    ofn.Flags   = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST; 

    if (GetOpenFileNameA(&ofn)) 
    { 
     src = filename; //<----------Save filepath in global variable 
     return true; 
    } 
    return false; 
} 

コメント行にブレークポイントを配置する際に、私はこの時点で私にあった「SRC」と同様に「ファイル名」、アジア起源の識別不能な文字の値を調べることができます。なぜこれが起こるのですか?これはコンバージョンの問題ですか?

EDIT:

迅速な回答に感謝し、いくつかのコメント、コードが完全に機能しています。非常に直接的なソリューションであるHans Passantにも感謝しています。また、関数を書き直し、間違いを説明し、処理方法を教えてくれたCody Greyにも非常に感謝しています。私はまだwinapiを学ぶための私の最初の措置をとっているので、この情報は将来のプログラムで私をうまく提供します。

+0

wchar_tの代わりに 'char filename [MAX_PATH];'を試してください –

+0

LPSTRキャストは非常に邪悪なので、間違っているとコンパイラは警告していません。あなたがそれを間違ってやってしまうのをやめさせてくれませ代わりにOPENFILENAMEWとGetOpenFileNameWを使用し、L "blabla"を使用してワイド文字列リテラルを生成します。 –

+0

'GetOpenFileNameA'は 'GetOpenFileName'のANSIサブ機能ですので、コードがUnicodeとして構築されていないことを確認する必要があります。そして、あなたは 'GetOpenFileNameA'の代わりに 'GetOpenFileName'を使うべきです、良いサブ機能の選択は自動的に行われます。 – Gwen

答えて

3

これは、ANSIとUnicodeの文字タイプが混在しているために発生する古典的なバグです。その特徴は、あなたが描いている通り、アジア系のランダムな文字が文字列に現れることです。

コードをすばやく確認すると、すぐに問題が明らかになります。 のANSIバージョンと、データ構造のANSIバージョンを使用しています。OPENFILENAMEA - filenameの配列はワイド文字(wchar_t)で構成されています。 Win32では、A - 接尾辞付きの型は常にANSIであり、1バイトのchar型を使用する必要があります。 W - 接尾辞付きの型は常にUnicodeであり、2バイトのwchar_t型を使用する必要があります。明示的な変換なしで2つを混在させることはできません。および/またはWideCharToMultiByteを使用したです。

明示的なキャストを使用してシャットダウンしていない場合、コンパイラはこの型の不一致エラーを検出したことに注意してください。

現代では、Unicodeを常にサポートしたいので、常にWの接尾辞のAPIを使用する必要があります。世界はASCIIではなく、Windows NTとWindows 98/MEに切り替えたすべての人が死んで埋葬されたときには、Windows ANSIエンコーディングは時代遅れになりました。次のように

ので(私もゼロメモリにC++言語の構文を使用してのように、だけでなく、他のいくつかのイディオムを変更して、他の方法でコードをクリーンアップするために自由を取った)あなたのコードを書き換える:

std::wstring src; 

bool open() 
{ 
    const std::wstring title = L"Select a File"; 
    std::wstring filename(MAX_PATH, L'\0'); 

    OPENFILENAMEW ofn = { }; 
    ofn.lStructSize  = sizeof(ofn); 
    ofn.hwndOwner  = NULL; 
    ofn.lpstrFilter  = L"Music (.mp3)\0*.mp3\0All\0*.*\0"; 
    ofn.lpstrFile  = &filename[0]; // use the std::wstring buffer directly 
    ofn.nMaxFile  = MAX_PATH; 
    ofn.lpstrTitle  = title.c_str(); 
    ofn.Flags   = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST; 

    if (GetOpenFileNameW(&ofn)) 
    { 
     src = filename; //<----------Save filepath in global variable 
     return true; 
    } 
    return false; 
} 

毎回Wを明示的に入力する必要がないようにするには、UNICODE_UNICODEの両方がプロジェクト用にグローバルに定義されていることを確認してください。これを行う最善の方法は、これらのシンボルを事前定義できるプロジェクトプロパティを使用することです。それ以外の場合は、プリコンパイル済みヘッダーの先頭に定義できます。これにより、接尾辞を省略した場合でも、Wの接尾辞付きの関数と型の変形が常にになります。だから、単にGetOpenFileNameOPENFILENAMEと言うことができます。 Windowsヘッダーファイルのマクロが解決を処理します。

これは、ワイド文字リテラルに接頭辞Lを付加するのを忘れた場合に、コンパイラが型の不一致エラーを生成するということです。これは一般的な誤りです。そう。 (もちろん、これはコンパイラの警告を無音にするために明示的なキャストを使用する悪い習慣から抜け出すことを前提としています。)

+0

エラーがどのようになったか、問題を解決する方法、およびこの解決方法が他のものの上に示唆される理由を説明することを非常に参考にして説明します。どうもありがとう。 – qwarten

関連する問題