2016-08-11 1 views
0

この動作を説明する方法はほとんど分かりません。このため、私自身は答えを見つけることができません - この問題の名前を付ける方法はわかりません。返信時にC++のwin32api値のエンコーディングが壊れる

OPENFILENAME GuiUtils::ChooseFileDialog(HWND hwnd) 
{ 
    OPENFILENAME ofn; 
    char szFile[260]; 
    ZeroMemory(&ofn, sizeof(ofn)); 
    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = hwnd; 
    ofn.lpstrFile = (LPWSTR)szFile; 
    ofn.lpstrFile[0] = '\0'; 
    ofn.nMaxFile = sizeof(szFile); 
    ofn.nFilterIndex = 1; 
    ofn.lpstrFileTitle = NULL; 
    ofn.nMaxFileTitle = 0; 
    ofn.lpstrFilter = TEXT("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"); 
    ofn.lpstrInitialDir = NULL; 
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 
    HANDLE hf; 

    // Display the Open dialog box. 
    if (GetOpenFileName(&ofn) == TRUE) 
    { 
     hf = CreateFile(ofn.lpstrFile, 
      GENERIC_READ, 
      0, 
      (LPSECURITY_ATTRIBUTES)NULL, 
      OPEN_EXISTING, 
      FILE_ATTRIBUTE_NORMAL, 
      (HANDLE)NULL); 
    } 
    return ofn; 
} 

I:私は、ファイルを開いて、ファイル名を取得するクラスメソッドを持っているいくつかの方法で、タイトルがmissleadingされるか質問が間違っているのであればお待ちくださいが、ここでは

が来ます

を:すべてが正しく enter image description here

私は、デバッガでの移動と呼び出し元の関数に戻ってジャンプすると何かがめちゃくちゃますエンコードされたように見えofn.lpstrFileを見て呼び出すクラスメソッド:

INT_PTR CALLBACK FormCreator::Callback(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (Message) 
    { 
    case WM_COMMAND: 
     if (LOWORD(wParam) == IDCHOOSEFILE) 
     { 
      GuiUtils *guiUtils = new GuiUtils(); 
      OPENFILENAME ofn = guiUtils->ChooseFileDialog(hwnd); 
      ORMFactory* db = new ORMFactory(); // value in debugger changes here 
      AbstractORM* sqlite = db->GetORMProvider(TEXT("SQLITE")); 
      this->databaseFileName = (wstring)ofn.lpstrFile; 
     } 
     break; 

    return 0; 
} 

enter image description here

は、誰かが私はこの問題を解決するためにここで間違っofn.lpstrFile、どのようにして聞かせていただけますか?あなたは、ファイル名を格納するスタックアレーszFileを使用している

+2

http://www.codeproject.com/Articles/76252/What-are-TCHAR-WCHAR-LPSTR-LPWSTR-LPCTSTR-etc – Ajay

+1

あなたが嘘をつきましたコンパイラはここで '(LPWSTR)szFile'となり、その嘘の避けられない結果が得られました。コンパイラに嘘をつけないでください。 –

答えて

5

あなたはGetOpenFileName()のUnicodeバージョンを使用していますしかし、あなたはそれにANSIバッファを与えて、選択したファイル名を格納します。バッファをlpstrFileフィールドに代入するときにバッファを型キャストして、この不一致を警告したコンパイラエラーを隠します。

バッファをcharからwchar_tに変更して型変換を取り除く必要があります。

ただし、修正しても、コードには他のエラーがあります。

ポピュレートされたOPENFILENAMEを呼び出し元に戻していますが、ChooseFileDialog()が終了するとスコープ外に出るローカルバッファを指しています。呼び出し元がlpstrFileフィールドにアクセスすると、という未定義の動作が呼び出されます。

ChooseFileDialog()は、成功するたびにファイルハンドルがリークしています(GetOpenFileName())。あなたはファイルハンドルで何もしておらず、閉じていません。そのため、ファイルをまったく開くべきではありません。

そして、あなたはコールバックに動的に合金化されたオブジェクトを漏らしています。

代わりに、より多くのこのような何かを試してみてください:

std::wstring GuiUtils::ChooseFileDialog(HWND hwnd) 
{ 
    OPENFILENAMEW ofn; 
    wchar_t szFile[MAX_PATH]; 
    ZeroMemory(&ofn, sizeof(ofn)); 
    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = hwnd; 
    ofn.lpstrFile = szFile; 
    ofn.lpstrFile[0] = '\0'; 
    ofn.nMaxFile = MAX_PATH; 
    ofn.nFilterIndex = 1; 
    ofn.lpstrFileTitle = NULL; 
    ofn.nMaxFileTitle = 0; 
    ofn.lpstrFilter = L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; 
    ofn.lpstrInitialDir = NULL; 
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 
    HANDLE hf; 

    // Display the Open dialog box. 
    if (!GetOpenFileNameW(&ofn)) 
     return L""; 

    // what is this for??? 
    /* 
    hf = CreateFileW(ofn.lpstrFile, 
      GENERIC_READ, 
      0, 
      NULL, 
      OPEN_EXISTING, 
      FILE_ATTRIBUTE_NORMAL, 
      NULL); 
    */ 

    return ofn.lpstrFile; 
} 

INT_PTR CALLBACK FormCreator::Callback(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) 
{ 
    switch (Message) 
    { 
    case WM_COMMAND: 
     if (LOWORD(wParam) == IDCHOOSEFILE) 
     { 
      GuiUtils guiUtils; 
      std::wstring fname = guiUtils.ChooseFileDialog(hwnd); 
      if (fname.empty()) break; 
      ORMFactory db; 
      AbstractORM* sqlite = db.GetORMProvider(L"SQLITE"); 
      this->databaseFileName = fname; 
     } 
     break; 
    } 

    return 0; 
} 
+0

詳細な説明とこのエラーを発見していただきありがとうございます。最後に、私がデバッガで見たような兆候が何であるかを教えてもらえますか?それで、将来私の問題をよりよく解決できるでしょうか? これは何らかのエンコードの問題だったと思いますか? – abdoe

+2

@abdoeこれはエンコーディングの問題ではありません。これはAPIの暴発的な誤用です。あなたはメモリとデータ型を誤って管理しています。呼び出し元のスクリーンショットに表示されているエラーは、もはや有効ではないメモリを検査しているためです。 –

+0

ありがとう – abdoe

1

ありがとうございました。 ChooseFileDialogメソッドが終了すると、すべてのスタック変数が破棄されます。スタック変数へのポインタを返すことは、未定義の動作です。

この行も奇妙である:

ofn.lpstrFile = (LPWSTR)szFile; 

あなたはwchar_tポインタにchar配列をキャストしています。ファイル名が129ワイド文字より大きい場合は、バッファオーバーフローが発生します。この問題を解決するための

、動的メモリ割り当てを使用します。

ofn.lpstrFile = new WCHAR[MAX_PATH]; 
ofn.nMaxFile = MAX_PATH; 

Callbackは、それはそれを使用して行われたときに、配列を解放する必要があります:

delete[] ofn.lpstrFile; 
+1

ダイナミックメモリを使用すると、より多くの問題が発生しますが、この例では解決します。これは良い解決策ではありません。 'wstring'を返すほうが安全で、スタックベースの配列を使って関数を続けることができます。 –

関連する問題