2012-05-04 19 views
8

tôi viết mã này để có được fileName để lưu tập tin của tôi:cách lưu tệp bằng GetSaveFileName trong win32?

#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; 
} 

Nhưng đầu ra là:

the path is : H 

tại sao? Tôi có làm điều gì sai ?
Tôi đang sử dụng Visual Studio 2008 trên Windows 7.

+1

+1 để có ví dụ hoàn chỉnh và câu hỏi được xây dựng tốt. –

Trả lời

8

dòng này:

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

nên sử dụng phiên bản char rộng của printf.

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

+1 bạn thắng ... lần này. :) –

+1

Vì phần còn lại của mã, bao gồm giá trị 'lpstrFile', dựa trên' _TCHAR', bạn nên sử dụng '_tprintf' thay vào đó:' _tprintf (_T ("đường dẫn là:% s \ n"), ofn .lpstrFile); ' –

+2

-1 Mã này vẫn còn nguy hiểm vì bộ đệm quá nhỏ. –

8

Vấn đề gốc rễ là ở những dòng này:

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

Điều này tạo ra một bộ đệm ký tự MAX_PATH, nhưng nó kể GetSaveFileName chức năng rằng đó là một bộ đệm của MAX_PATH rộng ký tự. Điều này có khả năng bị lỗi (hoặc âm thầm chà đạp bộ nhớ) khi ai đó chọn một tên đường dẫn dài.

Giveaway là dàn diễn viên. Đừng nói dối với trình biên dịch hoặc các thư viện. Họ không thích điều đó, và họ sẽ luôn nhận được sự trả thù của họ cuối cùng. Thay thế các dòng này bằng cách này:

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

Bây giờ tên tệp được chọn sẽ được trả về dưới dạng chuỗi ký tự rộng. câu trả lời Tony The Lion là đúng ở chỗ mà bạn cần phải sử dụng wprintf hơn printf để in chuỗi ký tự rộng:

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

Nếu bạn cần chuỗi bằng ký tự 8-bit thay vì ký tự rộng, bạn có thể sử dụng WideCharToMultiByte . Nhưng tôi sẽ chỉ gắn bó với các API nhân vật nói chung.

Không bao giờ cast trừ khi bạn biết chính xác nó làm gì và tại sao nó cần thiết trong trường hợp cụ thể của bạn.

-1

Cả hai đều sai, đó là vấn đề con trỏ/ngăn xếp C đơn giản.

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

Điều này gây nhầm lẫn mảng và con trỏ, bạn khai báo mảng trên ngăn xếp, nhưng sau đó thay đổi địa chỉ bộ nhớ để trỏ đến một chuỗi trống trong phần dữ liệu. Nói cách khác, tràn bộ đệm.

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

Điều này khai báo một mảng ký tự trên ngăn xếp và khởi tạo tất cả các thành phần vào bộ kết thúc rỗng.

Hy vọng điều đó sẽ hữu ích!

+0

Chuỗi ký tự ở bên phải của bộ khởi tạo mảng có ý nghĩa đặc biệt.Câu lệnh 'char szFileName [MAX_PATH] =" "'; * không * tạo con trỏ. Nó khởi tạo 'szFileName [0] thành '\ 0'', tức là null terminator. –

Các vấn đề liên quan