0

我想添加一个选择文件对话框到我的项目,现在只能由用户输入文件名。C++ win32控制台应用程序使用Windows API添加“选择文件”对话框

我做了一些搜索,它似乎Windows API与GetOpenFileName函数是我这样做的最简单的方法。但是,当我复制&粘贴示例代码无论是从MSDN或其他网站,我有一些构建错误。

我使用的Visual Studio 2017而我使用的示例代码是从http://www.cplusplus.com/forum/windows/169960/

#include <iostream> 

#ifndef NOMINMAX 
#define NOMINMAX 
#endif 
#include <windows.h> 

int main() 
{ 
    char filename[ MAX_PATH ]; 

    OPENFILENAME ofn; 
    ZeroMemory(&filename, sizeof(filename)); 
    ZeroMemory(&ofn,  sizeof(ofn)); 
    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = NULL; // If you have a window to center over, put its HANDLE here 
    ofn.lpstrFilter = "Text Files\0*.txt\0Any File\0*.*\0"; 
    ofn.lpstrFile = filename; 
    ofn.nMaxFile  = MAX_PATH; 
    ofn.lpstrTitle = "Select a File, yo!"; 
    ofn.Flags  = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST; 

    if (GetOpenFileNameA(&ofn)) 
    { 
    std::cout << "You chose the file \"" << filename << "\"\n"; 
    } 
    else 
    { 
    // All this stuff below is to tell you exactly how you messed up above. 
    // Once you've got that fixed, you can often (not always!) reduce it to a 'user cancelled' assumption. 
    switch (CommDlgExtendedError()) 
    { 
     case CDERR_DIALOGFAILURE : std::cout << "CDERR_DIALOGFAILURE\n"; break; 
     case CDERR_FINDRESFAILURE : std::cout << "CDERR_FINDRESFAILURE\n"; break; 
     case CDERR_INITIALIZATION : std::cout << "CDERR_INITIALIZATION\n"; break; 
     case CDERR_LOADRESFAILURE : std::cout << "CDERR_LOADRESFAILURE\n"; break; 
     case CDERR_LOADSTRFAILURE : std::cout << "CDERR_LOADSTRFAILURE\n"; break; 
     case CDERR_LOCKRESFAILURE : std::cout << "CDERR_LOCKRESFAILURE\n"; break; 
     case CDERR_MEMALLOCFAILURE : std::cout << "CDERR_MEMALLOCFAILURE\n"; break; 
     case CDERR_MEMLOCKFAILURE : std::cout << "CDERR_MEMLOCKFAILURE\n"; break; 
     case CDERR_NOHINSTANCE  : std::cout << "CDERR_NOHINSTANCE\n";  break; 
     case CDERR_NOHOOK   : std::cout << "CDERR_NOHOOK\n";   break; 
     case CDERR_NOTEMPLATE  : std::cout << "CDERR_NOTEMPLATE\n";  break; 
     case CDERR_STRUCTSIZE  : std::cout << "CDERR_STRUCTSIZE\n";  break; 
     case FNERR_BUFFERTOOSMALL : std::cout << "FNERR_BUFFERTOOSMALL\n"; break; 
     case FNERR_INVALIDFILENAME : std::cout << "FNERR_INVALIDFILENAME\n"; break; 
     case FNERR_SUBCLASSFAILURE : std::cout << "FNERR_SUBCLASSFAILURE\n"; break; 
     default     : std::cout << "You cancelled.\n"; 
    } 
    } 
} 

当我&复制粘贴到VS,它显示以下内容:

Severity Code Description Project File Line Suppression State 
Error C2440 '=': cannot convert from 'char [260]' to 'LPWSTR' ConsoleApplication1 c:\users\xfan0\documents\visual studio 2017\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp 18 
Severity Code Description Project File Line Suppression State 
Error C2440 '=': cannot convert from 'const char [19]' to 'LPCWSTR' ConsoleApplication1 c:\users\xfan0\documents\visual studio 2017\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp 20 
Severity Code Description Project File Line Suppression State 
Error C2664 'BOOL GetOpenFileNameA(LPOPENFILENAMEA)': cannot convert argument 1 from 'OPENFILENAME *' to 'LPOPENFILENAMEA' ConsoleApplication1 c:\users\xfan0\documents\visual studio 2017\projects\consoleapplication1\consoleapplication1\consoleapplication1.cpp 23 

Severity Code Description Project File Line Suppression State 
Error (active) E0167 argument of type "OPENFILENAME *" is incompatible with parameter of type "LPOPENFILENAMEA" ConsoleApplication1 c:\Users\XFAN0\Documents\Visual Studio 2017\Projects\ConsoleApplication1\ConsoleApplication1\ConsoleApplication1.cpp 23 

试过搜索但没有找到我的运气:(

+0

您的构建默认为期望宽字符字符串,但您使用的是MBCS字符串。您可以在调用Windows API时将代码更改为使用宽字符串,也可以更改项目设置(项目属性 - >常规 - >字符集 - >使用多字节字符集)。 –

+0

在某些地方,您抓取的示例代码明确调用了MBCS版本(例如'GetOpenFileNameA'),但它并不一致(例如,“OPENFILENAME”默认为“OPENFILENAMEW”而不是“OPENFILENAMEA”)。在现代Windows程序中,使用API​​的宽字符串版本是首选。 MBCS功能主要是为了向后兼容,并且有其局限性。 –

+0

很酷。其实我试过这个设置,但是当我测试另一个例子的时候,它不起作用。 –

回答

1

微软通常提倡的方法是使用他们的“通用文本”宏,所以你的st环文字是这样的:

ofn.lpstrFilter = _T("Text Files\0*.txt\0Any File\0*.*\0"); 
ofn.lpstrTitle = _T("Select a File, yo!"); 

这样,您就可以建立窄或宽字符串(后者通过定义UNICODE_UNICODE)。 _T将映射为窄字符版本的任何内容,对于宽字体版本则不会映射到L,因此您可以根据自己的创建方式自动获取正确类型的字符串。

要使用此功能,请包括<tchar.h>

例如:

#include <iostream> 
#include <tchar.h> 

#ifndef NOMINMAX 
#define NOMINMAX 
#endif 
#include <windows.h> 

int main() 
{ 
    char filename[ MAX_PATH ]; 

    OPENFILENAME ofn; 
    ZeroMemory(&filename, sizeof(filename)); 
    ZeroMemory(&ofn,  sizeof(ofn)); 
    ofn.lStructSize = sizeof(ofn); 
    ofn.hwndOwner = NULL; // If you have a window to center over, put its HANDLE here 
    ofn.lpstrFilter = _T("Text Files\0*.txt\0Any File\0*.*\0"); 
    ofn.lpstrFile = filename; 
    ofn.nMaxFile  = MAX_PATH; 
    ofn.lpstrTitle = _T("Select a File, yo!"); 
    ofn.Flags  = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST; 

    if (GetOpenFileName(&ofn)) 
    { 
    std::cout << "You chose the file \"" << filename << "\"\n"; 
    } 
    else 
    { 
    // All this stuff below is to tell you exactly how you messed up above. 
    // Once you've got that fixed, you can often (not always!) reduce it to a 'user cancelled' assumption. 
    switch (CommDlgExtendedError()) 
    { 
     case CDERR_DIALOGFAILURE : std::cout << "CDERR_DIALOGFAILURE\n"; break; 
     case CDERR_FINDRESFAILURE : std::cout << "CDERR_FINDRESFAILURE\n"; break; 
     case CDERR_INITIALIZATION : std::cout << "CDERR_INITIALIZATION\n"; break; 
     case CDERR_LOADRESFAILURE : std::cout << "CDERR_LOADRESFAILURE\n"; break; 
     case CDERR_LOADSTRFAILURE : std::cout << "CDERR_LOADSTRFAILURE\n"; break; 
     case CDERR_LOCKRESFAILURE : std::cout << "CDERR_LOCKRESFAILURE\n"; break; 
     case CDERR_MEMALLOCFAILURE : std::cout << "CDERR_MEMALLOCFAILURE\n"; break; 
     case CDERR_MEMLOCKFAILURE : std::cout << "CDERR_MEMLOCKFAILURE\n"; break; 
     case CDERR_NOHINSTANCE  : std::cout << "CDERR_NOHINSTANCE\n";  break; 
     case CDERR_NOHOOK   : std::cout << "CDERR_NOHOOK\n";   break; 
     case CDERR_NOTEMPLATE  : std::cout << "CDERR_NOTEMPLATE\n";  break; 
     case CDERR_STRUCTSIZE  : std::cout << "CDERR_STRUCTSIZE\n";  break; 
     case FNERR_BUFFERTOOSMALL : std::cout << "FNERR_BUFFERTOOSMALL\n"; break; 
     case FNERR_INVALIDFILENAME : std::cout << "FNERR_INVALIDFILENAME\n"; break; 
     case FNERR_SUBCLASSFAILURE : std::cout << "FNERR_SUBCLASSFAILURE\n"; break; 
     default     : std::cout << "You cancelled.\n"; 
    } 
    } 
} 

为了得到一个 “保存” 名而不是,只是改变了GetOpenFilenameGetSaveFilename。虽然在OPENFILENAME中可能会传递的标志存在一些差异 - 例如,在打开文件时通过OFN_FILEMUSTEXIST很常见,但几乎从不想在保存文件时。

+0

为了保存文件对话框,有没有像“OPENFILENAME”这样的简单方法? –

+0

@XiaofengFan:[GetSaveFilename](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646928.aspx) –

+0

有没有我可以学习的例子?我已经从MSDN检查了这个文档,但是给出的例子也是其他东西的一部分。所以我无法理解给出的例子(在这个阶段)。将非常感谢GetSaveFileName使用的一些可执行示例。 –

相关问题