0

J'essaie d'ajouter une boîte de dialogue choisir un fichier à mon projet qui peut maintenant prendre seulement le nom de fichier entré par l'utilisateur.C++ win32 console app ajouter un "choisir un fichier" boîte de dialogue en utilisant Windows api

J'ai fait quelques recherches et il semble que l'API Windows avec la fonction GetOpenFileName est la façon la plus simple pour moi de le faire. Toutefois, lorsque je copie & coller l'exemple de code que ce soit à partir de MSDN ou d'autres sites Web, j'ai eu quelques erreurs de construction.

J'utilise Visual Studio 2017. Et l'exemple de code j'est de 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"; 
    } 
    } 
} 

Lorsque je copie & pâte vs, il montre les éléments suivants:

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 

Essayé de rechercher pour cela, mais n'avait pas trouvé ma chance :(

+0

Par défaut, votre génération attend des chaînes de caractères larges, mais vous utilisez des chaînes MBCS. Vous pouvez modifier votre code pour utiliser des chaînes de caractères larges lorsque vous appelez les API Windows ou vous pouvez modifier les paramètres de votre projet (Propriétés du projet -> Général -> Jeu de caractères -> Utiliser le jeu de caractères multi-octets). –

+0

Dans certains cas, l'exemple de code que vous avez saisi appelle explicitement les versions MBCS (par exemple, GetOpenFileNameA), mais ne le fait pas de manière cohérente (par exemple, OPENFILENAME est défini par défaut sur OPENFILENAMEW plutôt que OPENFILENAMEA). Dans les programmes Windows modernes, l'utilisation des versions à grande chaîne de l'API est préférable. La fonctionnalité MBCS est principalement pour la rétrocompatibilité, et il a des limites. –

+0

Cool. En fait, j'ai essayé ce réglage mais c'est quand j'ai testé un autre exemple que ça n'a pas fonctionné. –

Répondre

1

La méthode que Microsoft préconise normalement est d'utiliser leurs macros "texte générique", de sorte que votre st anneau littéraux se présente comme suit:

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

De cette façon, vous pouvez construire des chaînes de caractères étroits ou larges (ce dernier en définissant UNICODE et _UNICODE). Le _T ne correspondra à rien pour une construction à caractères étroits, et à L pour une construction à caractères larges, donc vous obtiendrez automatiquement le bon type de chaîne pour la façon dont vous construisez.

Pour l'utiliser, vous devez inclure <tchar.h>.

Par exemple:

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

Pour obtenir un nom de fichier « sauver » au lieu, il suffit de changer le GetOpenFilename-GetSaveFilename. Il y a quelques différences dans les drapeaux que vous allez probablement passer dans OPENFILENAME - par exemple, il est assez courant de passer OFN_FILEMUSTEXIST lorsque vous ouvrez un fichier, mais vous ne le souhaitez presque jamais lorsque vous enregistrez un fichier .

+0

Pour enregistrer la boîte de dialogue, existe-t-il un moyen simple comme "OPENFILENAME" de le faire? –

+0

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

+0

Existe-t-il un exemple avec lequel je peux étudier? J'ai vérifié cette documentation de MSDN mais l'exemple donné était aussi une partie d'autres choses. Donc je n'ai pas pu comprendre l'exemple donné (à ce stade).Appréciera vraiment quelques exemples exécutables sur l'utilisation de GetSaveFileName. –