2012-05-04 26 views
8

私は私のファイルを保存するファイル名を取得するには、このコードを書く:Win32でGetSaveFileNameを使ってファイルを保存する方法は?

#include "stdafx.h" 
#include <windows.h> 


int _tmain(int argc, _TCHAR* argv[]) 
{    
    OPENFILENAME ofn; 

    char szFileName[MAX_PATH] = ""; 

    ZeroMemory(&ofn, sizeof(ofn)); 

    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = NULL; 
    ofn.lpstrFilter = (LPCWSTR)L"Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0"; 
    ofn.lpstrFile = (LPWSTR)szFileName; 
    ofn.nMaxFile = MAX_PATH; 
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; 
    ofn.lpstrDefExt = (LPCWSTR)L"txt"; 

    GetSaveFileName(&ofn); 
    printf("the path is : %s\n", ofn.lpstrFile); 
    getchar(); 
    return 0; 
} 

をしかし、出力は次のとおりです。

the path is : H 

なぜですか?私は何か間違っているのですか?
私はこのラインのWindows 7

+1

+1完全な例と正式な質問。 –

答えて

8

にVisual Studio 2008を使用しています:

printf("the path is : %s\n", ofn.lpstrFile); 

はprintf関数のワイド文字版を使用する必要があります。

wprintf(L"the path is : %s\n", ofn.lpstrFile); 
+1

+1今回は...この時間。 :) –

+1

'lpstrFile'を含む残りのコードは' _TCHAR'に基づいているので、 '_tprintf'を使うべきです:' _tprintf(_T( "パスは%s \ n")、ofn .lpstrFile); ' –

+2

-1このコードは、バッファーが小さすぎるため、依然として危険です。 –

8

根本的な問題は、これらの行にあります。

char szFileName[MAX_PATH] = ""; 
... 
ofn.lpstrFile = (LPWSTR)szFileName; 
ofn.nMaxFile = MAX_PATH; 

これは、MAX_PATH文字のバッファを作成しますが、それはそれはMAX_PATH ワイド文字のバッファのGetSaveFileName機能を伝えます。これは、誰かが長いパス名を選択したときに、クラッシュする(またはメモリを黙って踏みにじる)可能性があります。

ギフトはキャストです。コンパイラやライブラリに嘘をつけないでください。彼らはそれが好きではなく、彼らは常に最後に彼らの復讐を得るでしょう。これでこれらの行を置き換えます

WCHAR szFileName[MAX_PATH] = L""; 
... 
ofn.lpstrFile = szFileName; // no cast needed 
ofn.nMaxFile = MAX_PATH; 

は今、選択したファイル名は、ワイド文字の文字列として返されます。トニー・ライオンの答えはあなたがワイド​​文字の文字列を印刷するwprintfではなくprintfを使用する必要があるということで正しいです:

wprintf(L"the path is : %s\n", ofn.lpstrFile); // though I'd use szFileName at this point 

あなたの代わりにワイド文字の8ビット文字の文字列が必要な場合は、WideCharToMultiByteを使用することができます。しかし、私は一般的にワイドキャラクターAPIに固執します。

実際に何が行われているのか、特定のケースで必要な理由がわからない限り、キャストしないでください。

-1

あなたはどちらも間違っています。シンプルなCのポインタ/スタックの問題です。

// WRONG: 
char szFileName[MAX_PATH] = ""; 

これは、配列とポインタを混乱させる、あなたは、スタック上の配列を宣言したが、その後、データセクション内の空の文字列を指すようにそのメモリアドレスを変更します。つまり、バッファがオーバーフローします。

// RIGHT: 
char szFileName[MAX_PATH]; 
ZeroMemory(szFileName, MAX_PATH); 

これは、スタック上に文字配列を宣言し、すべての要素をNULLターミネータに初期化します。

希望に役立ちます!

+0

配列初期化子の右側にあるリテラル文字列は特別な意味を持ちます。ステートメント 'char szFileName [MAX_PATH] =" "';ポインタを作成しません。 'szFileName [0]を '\ 0'、つまりヌルターミネータに初期化します。 –

関連する問題