La plus grande erreur que vous faites est le mélange ANSI et Unicode ensemble. Vous utilisez les tampons char[]
et les tapez en les affectant aux pointeurs LPWSTR
afin de les affecter aux champs OPENFILENAME
. Puisque vous utilisez la version TCHAR
de l'API, cela signifie que votre projet est compilé pour Unicode, pas pour ANSI. Ainsi, l'API attend des buffers Unicode et sortira des chaînes Unicode. Ce qui signifie également que vous dites l'API qui deux fois l'espace alloué de vos tampons est disponible pour recevoir des caractères, puisque vous définissez les ofn.nMaxFile
et ofn.nMaxFileTitle
champs à octet compte au lieu de caractère compte. Vous pouvez donc provoquer des dépassements de tampon.
Vous ne pouvez pas simplement convertir un tampon de 8 bits en un type de données de 16 bits. Vous devez d'abord utiliser le type de données correct pour votre tampon et vous débarrasser des types-types. Dans ce cas, cela signifie utiliser les tampons WCHAR
/wchar_t
(ou au moins TCHAR
) au lieu des tampons char
. Mais puisque vous utilisez char
dans vos paramètres de fonction, vous devez utiliser la version ANSI de l'API au lieu de la version TCHAR
/Unicode. Lorsque vous sélectionnez plusieurs fichiers, en particulier des fichiers avec des noms de fichiers longs, les données de caractères résultantes peuvent facilement dépasser la taille de votre tampon de longueur fixe. Comme les États OPENFILENAME
documentation:
lpstrFile
Type: LPTSTR
The file name used to initialize the File Name edit control. The first character of this buffer must be NULL if initialization is not necessary. When the GetOpenFileName
or GetSaveFileName
function returns successfully, this buffer contains the drive designator, path, file name, and extension of the selected file.
If the OFN_ALLOWMULTISELECT
flag is set and the user selects multiple files, the buffer contains the current directory followed by the file names of the selected files. For Explorer-style dialog boxes, the directory and file name strings are NULL separated, with an extra NULL character after the last file name. For old-style dialog boxes, the strings are space separated and the function uses short file names for file names with spaces. You can use the FindFirstFile
function to convert between long and short file names. If the user selects only one file, the lpstrFile
string does not have a separator between the path and file name.
If the buffer is too small, the function returns FALSE
and the CommDlgExtendedError
function returns FNERR_BUFFERTOOSMALL
. In this case, the first two bytes of the lpstrFile
buffer contain the required size, in bytes or characters.
nMaxFile
Type: DWORD
The size, in characters, of the buffer pointed to by lpstrFile
. The buffer must be large enough to store the path and file name string or strings, including the terminating NULL character. The GetOpenFileName
and GetSaveFileName
functions return FALSE
if the buffer is too small to contain the file information. The buffer should be at least 256 characters long.
Vous ne prenez pas en tenir compte. 256 (préférable d'utiliser 260, alias MAX_PATH
) est OK pour sélectionner un seul fichier, mais peut ne pas être OK pour sélectionner plusieurs fichiers. Si GetOpenFileName()
échoue avec FNERR_BUFFERTOOSMALL
, vous devrez réallouer votre tampon et appeler à nouveau GetOpenFileName()
.
Cela dit, essayer quelque chose comme ceci:
BOOL OpenBmpFiles(char **filePath, char** fileNames, HWND hwnd)
{
*filePath = NULL;
*fileNames = NULL;
size_t iMaxFileSize = MAX_PATH;
char *lpFileBuffer = (char*) malloc(iMaxFileSize);
if (!lpFileBuffer)
return FALSE;
char szFileTitle[MAX_PATH];
BOOL bResult = FALSE;
OPENFILENAMEA ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile = lpFileBuffer;
ofn.nMaxFile = iMaxFileSize;
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrTitle = "Open BMP File";
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
do
{
//
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of lpstrFile to initialize itself.
//
ofn.lpstrFile[0] = '\0';
// show the common dialog "Open BMP File"
if (GetOpenFileNameA(&ofn))
break;
// if cancel, exit
if (CommDlgExtendedError() != FNERR_BUFFERTOOSMALL)
goto cleanup;
// reallocate the buffer and try again
iMaxFileSize = * (WORD*) lpFileBuffer;
char *lpNewFileBuffer = (char*) realloc(lpFileBuffer, iMaxFileSize);
if (!lpNewFileBuffer)
goto cleanup;
lpFileBuffer = lpNewFileBuffer;
ofn.lpstrFile = lpFileBuffer;
ofn.nMaxFile = iMaxFileSize;
}
while (true);
if (lpFileBuffer[ofn.nFileOffset-1] != '\0')
{
MessageBox(hwnd, TEXT("Single Selection"), TEXT("Open Debug 1"), MB_OK);
// copy the single filename and make sure it is double-null terminated
size_t len = strlen(&lpFileBuffer[ofn.nFileOffset]) + 2;
*fileNames = (char*) malloc(len);
if (!*fileNames)
goto cleanup;
strncpy(*fileNames, &lpFileBuffer[ofn.nFileOffset], len);
// copy the directory path and make sure it is null terminated
lpFileBuffer[ofn.nFileOffset] = '\0';
*filePath = strdup(lpFileBuffer);
if (!*filePath)
{
free(*fileNames);
*fileNames = NULL;
goto cleanup;
}
}
else
{
MessageBox(hwnd, TEXT("Multiple Selection"), TEXT("Open Debug 2"), MB_OK);
// copy the directory path, it is already null terminated
*filePath = strdup(lpFileBuffer);
if (!*filePath)
goto cleanup;
// copy the multiple filenames, they are already double-null terminated
size_t len = (ofn.nMaxFile - ofn.nFileOffset);
*fileNames = (char*) malloc(len);
if (!*fileNames)
{
free(*filePath);
*filePath = NULL;
goto cleanup;
}
// have to use memcpy() since the filenames are null-separated
memcpy(*fileNames, &lpFileBuffer[ofn.nFileOffset], len);
}
bResult = TRUE;
cleanup:
free(lpFileBuffer);
return bResult;
}
Ensuite, vous pouvez l'utiliser comme ceci:
char *path, *filenames;
if (OpenBmpFiles(&path, &filenames, hwnd))
{
char *filename = filenames;
do
{
// use path + filename as needed...
/*
char *fullpath = (char*) malloc(strlen(path)+strlen(filename)+1);
PathCombineA(fullpath, path, filename);
doSomethingWith(fullpath);
free(fullpath);
*/
filename += (strlen(filename) + 1);
}
while (*filename != '\0');
free(path);
free(filenames);
}
MISE À JOUR: alternativement, pour simplifier l'utilisation de les noms de fichiers retournés, vous pourriez faire quelque chose de plus comme ceci:
BOOL OpenBmpFiles(char** fileNames, HWND hwnd)
{
*fileNames = NULL;
size_t iMaxFileSize = MAX_PATH;
char *lpFileBuffer = (char*) malloc(iMaxFileSize);
if (!lpFileBuffer)
return FALSE;
char szFileTitle[MAX_PATH];
BOOL bResult = FALSE;
OPENFILENAMEA ofn;
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFilter = "Bitmap Files (*.bmp)\0*.bmp\0\0";
ofn.nFilterIndex = 1;
ofn.lpstrFile = lpFileBuffer;
ofn.nMaxFile = iMaxFileSize;
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = MAX_PATH;
ofn.lpstrTitle = "Open BMP File";
ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
do
{
//
// Set lpstrFile[0] to '\0' so that GetOpenFileName does not
// use the contents of lpstrFile to initialize itself.
//
ofn.lpstrFile[0] = '\0';
// show the common dialog "Open BMP File"
if (GetOpenFileNameA(&ofn))
break;
// if cancel, exit
if (CommDlgExtendedError() != FNERR_BUFFERTOOSMALL)
goto cleanup;
// reallocate the buffer and try again
iMaxFileSize = * (WORD*) lpFileBuffer;
char *lpNewFileBuffer = (char*) realloc(lpFileBuffer, iMaxFileSize);
if (!lpNewFileBuffer)
goto cleanup;
lpFileBuffer = lpNewFileBuffer;
ofn.lpstrFile = lpFileBuffer;
ofn.nMaxFile = iMaxFileSize;
}
while (true);
if (lpFileBuffer[ofn.nFileOffset-1] != '\0')
{
MessageBox(hwnd, TEXT("Single Selection"), TEXT("Open Debug 1"), MB_OK);
// copy the single filename and make sure it is double-null terminated
size_t len = strlen(lpFileBuffer) + 2;
*fileNames = (char*) malloc(len);
if (!*fileNames)
goto cleanup;
strncpy(*fileNames, lpFileBuffer, len);
}
else
{
MessageBox(hwnd, TEXT("Multiple Selection"), TEXT("Open Debug 2"), MB_OK);
// calculate the output buffer size
char *path = lpFileBuffer;
size_t pathLen = strlen(path);
bool slashNeeded = ((path[pathLen-1] != '\\') && (path[pathLen-1] != '/'));
size_t len = 1;
char *filename = &lpFileBuffer[ofn.nFileOffset];
while (*filename != '\0')
{
int filenameLen = strlen(filename);
len += (pathLen + filenameLen + 1);
if (slashNeeded) ++len;
filename += (filenameLen + 1);
}
// copy the filenames and make sure they are double-null terminated
*fileNames = (char*) malloc(len);
if (!*fileNames)
goto cleanup;
char *out = *fileNames;
filename = &lpFileBuffer[ofn.nFileOffset];
while (*filename != '\0')
{
strncpy(out, path, pathLen);
out += pathLen;
if (slashNeeded) *out++ = '\\';
int filenameLen = strlen(filename);
strncpy(out, filename, filenameLen);
out += filenameLen;
*out++ = '\0';
filename += (filenameLen + 1);
}
*out = '\0';
}
bResult = TRUE;
cleanup:
free(lpFileBuffer);
return bResult;
}
char *filenames;
if (OpenBmpFiles(&filenames, hwnd))
{
char *filename = filenames;
do
{
// use filename as needed...
/*
doSomethingWith(filename);
*/
filename += (strlen(filename) + 1);
}
while (*filename != '\0');
free(filenames);
}
Passer 'pTest' avec valeur autorisée, autrement dit quelque chose comme' int pTest; OpenBmpFile ((char *) fichier, (char *) fichier2, & pTest, hWnd); ' – LPs
Merci, pour une raison quelconque, il dit" Sélection multiple "même lorsque j'ouvre une seule image .bmp. :/J'ai eu ce problème pendant une journée entière j'en ai vraiment marre. Si seulement WinAPI peut simplifier les choses ... bien que ce soit une vieille langue après tout. – Jason