2017-03-15 1 views
0

J'ai trouvé ce morceau de code en ligne qui promet de séparer les données chargées dans le tampon, j'en ai besoin pour pouvoir afficher chaque image .bmp individuellement sur l'écran.Problème de séparation des données dans le tampon (WinAPI)

BOOL OpenBmpFile(char* filePath, char* fileName, int* offset, HWND hwnd) 
{ 
    OPENFILENAME ofn;    
    char szFileName[256];  
    char szFilePath[256]; 
    BOOL FileOK;   

    memset(&ofn, 0, sizeof(ofn)); 
    ofn.lStructSize = sizeof(OPENFILENAME); 
    ofn.hwndOwner = hwnd; 
    ofn.lpstrFilter = TEXT("Bitmap Files (*.bmp)\0*.bmp\0\0"); 
    ofn.nFilterIndex = 1; 
    strcpy(szFilePath, "*.bmp"); 
    ofn.lpstrFile = (LPWSTR)szFilePath; 
    // 
    // Set lpstrFile[0] to '\0' so that GetOpenFileName does not 
    // use the contents of szFile to initialize itself. 
    // 
    ofn.lpstrFile[0] = '\0'; 
    ofn.nMaxFile = sizeof(szFilePath); 
    ofn.lpstrFileTitle = (LPWSTR)szFileName; 
    ofn.nMaxFileTitle = sizeof(szFileName); 
    ofn.lpstrTitle = TEXT("Open BMP File"); 
    ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_ALLOWMULTISELECT | OFN_EXPLORER; 


    // show the common dialog "Open BMP File" 
    FileOK = GetOpenFileName(&ofn); 

    // if cancel, exit 
    if (!FileOK) 
     return FALSE; 

    // else store the selected filename 
    strcpy(fileName, szFileName); 
    //I use this because strcpy stops after the first NULL 
    memcpy(filePath, szFilePath, sizeof(szFilePath)); 
    *offset = ofn.nFileOffset; 

    if(szFilePath[ofn.nFileOffset-1] != '\0') 
    { 
    MessageBox(hwnd,L"Single Selection",L"Open Debug 1",MB_OK); 
    } 
    else 
    { 
    MessageBox(hwnd,L"Multiple Selection",L"Open Debug 2",MB_OK); 
    } 

    return TRUE; 
} 

Cependant, chaque fois que j'appelle cette fonction avec les résultats de ligne suivante dans une erreur:

OpenBmpFile((char*)file, (char*)file2, pTest, hWnd); 

Erreur: pTest est un nullptr; Je suppose que ma question est, comment puis-je utiliser cette fonction efficacement pour afficher mes images?

+0

Passer 'pTest' avec valeur autorisée, autrement dit quelque chose comme' int pTest; OpenBmpFile ((char *) fichier, (char *) fichier2, & pTest, hWnd); ' – LPs

+0

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

Répondre

0

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); 
} 
+0

Hey Remy, merci beaucoup pour l'information. Je savais que je ne pouvais pas sortir avec juste typecasting comme ça. La chose est, je suis assez nouveau à WinAPI et je ne suis pas un grand fan de sa syntaxe, bien que je me force à créer une application avec elle. Quoi qu'il en soit, pourriez-vous avoir un aperçu de mon code complet jusqu'à présent (ici: http://textuploader.com/dtchw) et me dire comment je devrais l'utiliser? Parce que ma fonction bitmap de chargement n'accepte pas le nom de fichier char * et je ne veux pas faire de typecasting. – Jason

+0

@FearlessHobbit ce code que je vous ai donné garde le répertoire et les noms de fichiers séparés, même pour une seule sélection. Votre boucle devra les combiner ensemble, comme avec ['PathCombine()'] (https://msdn.microsoft.com/fr-fr/library/windows/desktop/bb773571.aspx), avant d'appeler 'LoadAndBlitBitmap() '. J'ai choisi de ne pas faire le préfixe 'OpenBmpFiles()' chaque fichier 'filename' rapporté avec le même' chemin' pour économiser de la mémoire. Cependant, il serait trivial de changer ce comportement. –

+0

Ah d'accord, merci, je vais essayer de les combiner ensuite, j'espère que ce n'est pas trop difficile de les combiner, je vais vous faire savoir comment ça se passe. Je vous remercie beaucoup pour votre aide. En passant, juste pour vous le faire savoir, l'idée derrière mon programme est de faire une application qui charge des bitmaps en même temps en utilisant le multithreading. – Jason

0

nFileOffset est le décalage par rapport au début de lpstrFile au nom du fichier:

if lpstrFile points to the following string, "c:\dir1\dir2\file.ext" , this member contains the value 13 to indicate the offset of the "file.ext" string. If the user selects more than one file, nFileOffset is the offset to the first file name.

Selon cette étude, szFilePath[ofn.nFileOffset-1] pointera vers le \. lpStrFile est défini comme:

...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.

Ainsi, pour déterminer si l'utilisateur a sélectionné plus d'un fichier, allez à la fin de lpstrFile (c.-à la première null), puis vérifier s'il y a un autre null le suivant , sinon, l'utilisateur a sélectionné plusieurs fichiers.

Pour construire le chemin d'accès complet et le nom de fichier de chaque fichier, réutilisez la pièce jusqu'à nFileOffset et concaténéz chaque nom de fichier. Utilisez un débogueur pour inspecter ofn lors du retour pour tous les détails.

+1

Il convient également d'indiquer que le tampon 'szFilePath' dans le code OP est trop petit pour le résultat de la sélection multiple et que' CommDlgExtendedError() 'devrait être appelé pour vérifier la condition si le tampon est trop petit. – zett42

+0

Si vous lisez la documentation de l'indicateur 'OFN_ALLOWMULTISELECT', si plusieurs fichiers sont sélectionnés, le répertoire et la liste des noms de fichiers sont séparés par un caractère NUL, et' nFileOfset' pointe sur le premier nom de fichier, donc 'nFileOffset-1' pointerait au caractère NUL après le répertoire. Si un seul fichier est sélectionné, ce caractère NUL n'est pas présent. –

+0

@Remy Lebeau, petite correction: si 'OFN_ALLOWMULTISELECT' est spécifié, il y aura toujours une double nulle, même si un seul fichier est sélectionné. Si le drapeau n'est pas spécifié, il y aura toujours un seul nom de fichier et pas de double zéro. Il n'y a jamais de caractère nul après le répertoire; 'nFileOffset' pointe juste au début du nom de fichier dans le chemin complet et le nom de fichier. –

0

Microsoft recommande d'utiliser plus Common Item Dialog API moderne (disponible depuis Windows Vista) au lieu de GetOpenFileName().

Avec cette API vous n'avez pas les tracas de diviser le tampon de nom de fichier et de gérer la condition d'erreur si le tampon fourni est trop petit (ce qui vous obligerait à rappeler l'API avec un tampon plus grand). Dans votre code le tampon (szFilePath) est bien trop petit pour le résultat de la sélection multiple donc vous rencontrerez cette condition d'erreur très bientôt si l'utilisateur sélectionne plusieurs fichiers.

Je vais d'abord fournir un court exemple seulement pour montrer la séquence d'appels d'API pour utiliser IFileOpenDialog avec une sélection multiple.

court Exemple (plus bas pour le code complet)

Par souci de concision le code suivant a aucune erreur de manipulation du tout! Vous devez vérifier le HRESULT de chaque appel d'API COM pour l'échec, que je vais montrer dans l'exemple complet après.

// Prepare the file open dialog. 
CComPtr<IFileOpenDialog> dlg; 
dlg.CoCreateInstance(CLSID_FileOpenDialog); 

dlg->SetOptions(fos | FOS_ALLOWMULTISELECT); 

// Show the file open dialog. 
dlg->Show(hwndOwner); 
if(hr == S_OK) // If user clicked OK button... 
{ 
    CComPtr<IShellItemArray> items; 
    dlg->GetResults(&items); 

    DWORD numItems = 0; 
    items->GetCount(&numItems); 

    // Loop over all files selected by the user. 
    for(DWORD i = 0; i < numItems; ++i) 
    { 
     CComPtr<IShellItem> item; 
     items->GetItemAt(i, &item); 

     CComHeapPtr<WCHAR> path; 
     item->GetDisplayName(SIGDN_FILESYSPATH, &path); 

     std::wcout << std::wstring(path) << std::endl; 
    } 
} 

Exemple complet avec erreur de manipulation

Le code suivant montre comment utiliser IFileOpenDialog et comment combler l'écart entre les rapports d'erreurs de type C (HRESULT) et la façon dont C++ de le faire (exceptions).

Nous définissons d'abord une fonction ShowFileOpenDialog() qui enveloppe IFileOpenDialog pour faciliter son utilisation. Il renvoie un std::vector avec les chemins absolus des fichiers sélectionnés par l'utilisateur. Si l'utilisateur clique sur "annuler", le vecteur sera vide.En cas d'erreur, il déclenche une exception std::system_error.

#include <atlbase.h> 
#include <atlcom.h>  // CComHeapPtr 
#include <atlcomcli.h> // CComPtr 
#include <Shobjidl.h> // IFileOpenDialog 
#include <system_error> 
#include <vector> 
#include <string> 

void ThrowOnFail(HRESULT hr, char const* reason) 
{ 
    if(FAILED(hr)) 
     throw std::system_error(hr, std::system_category(), std::string("Could not ") + reason); 
} 

std::vector<std::wstring> ShowFileOpenDialog( 
    HWND hwndOwner, const std::vector<COMDLG_FILTERSPEC>& filter = {}, 
    FILEOPENDIALOGOPTIONS options = 0) 
{ 
    // Using CComPtr to automatically call IFileOpenDialog::Release() when scope ends. 
    CComPtr<IFileOpenDialog> dlg; 
    ThrowOnFail(dlg.CoCreateInstance(CLSID_FileOpenDialog), "instanciate IFileOpenDialog"); 

    if(!filter.empty()) 
     ThrowOnFail(dlg->SetFileTypes(filter.size(), filter.data()), "set filetypes filter"); 

    ThrowOnFail(dlg->SetOptions(options), "set options"); 

    HRESULT hr = dlg->Show(hwndOwner); 
    if(hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) 
     return {}; 
    ThrowOnFail(hr, "show IFileOpenDialog"); 

    CComPtr<IShellItemArray> items; 
    ThrowOnFail(dlg->GetResults(&items), "get results"); 

    DWORD numItems = 0; 
    ThrowOnFail(items->GetCount(&numItems), "get result count"); 

    std::vector<std::wstring> result; 
    result.reserve(numItems); 

    for(DWORD i = 0; i < numItems; ++i) 
    { 
     CComPtr<IShellItem> item; 
     ThrowOnFail(items->GetItemAt(i, &item), "get result item"); 

     // Using CComHeapPtr to automatically call ::CoTaskMemFree() when scope ends. 
     CComHeapPtr<WCHAR> path; 
     ThrowOnFail(item->GetDisplayName(SIGDN_FILESYSPATH, &path), "get result item display name"); 

     // Construct std::wstring directly in the vector. 
     result.emplace_back(path); 
    } 

    return result; 
} 

Comment appeler ce code et gérer l'exception:

#include <iostream> 

int main() 
{ 
    ::CoInitialize(0); // call once at application startup 

    try 
    { 
     HWND hwnd = nullptr; // In a GUI app, specify handle of parent window instead. 
     auto paths = ShowFileOpenDialog(hwnd, {{ L"Bitmap Files (*.bmp)", L"*.bmp" }}, 
             FOS_ALLOWMULTISELECT); 
     if(paths.empty()) 
     { 
      // Cancel button clicked. 
      std::cout << "No file(s) selected.\n"; 
     } 
     else 
     { 
      // OK button clicked. 
      for(const auto& path : paths) 
       std::wcout << path << L"\n"; 
     } 
    } 
    catch(std::system_error& e) 
    { 
     std::cout 
      << "Could not show 'file open dialog'." 
      << "\n\nCause: " << e.what() 
      << "\nError code: " << e.code() << "\n"; 
    } 

    ::CoUninitialize(); // match call of ::CoInitialize() 
    return 0; 
} 
+0

Bien que j'apprécie de signaler la nouvelle interface, ceci est C++ _ et j'aimerais voir la version C. –

+0

@Paul Question est étiqueté C++ ... – zett42