Я пытаюсь добавить в проект диалоговое окно выбора файла, которое теперь может принимать только имя файла, введенное пользователем.
Я провел некоторый поиск, и кажется, что 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";
}
}
}
Когда я копирую&вставить против, он показывает следующее:
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
Пытался найти это, но мне не повезло 🙁
Microsoft обычно рекомендует использовать их макросы «общего текста», чтобы ваши строковые литералы выглядели так:
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";
}
}
}
Чтобы получить «сохранить» имя файла, просто измените GetOpenFilename
в GetSaveFilename
, Есть несколько различий в флагах, которые вы, вероятно, передаете в OPENFILENAME — например, это довольно распространенная передача OFN_FILEMUSTEXIST
когда вы открываете файл, но вы почти никогда не хотите, когда вы сохраняете файл.
Других решений пока нет …