[WinAPI] Cum utilizam corect GetLastError?

Folosire Windows API in programe C/C++ (forum moderat)
Post Reply
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3776
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi

[WinAPI] Cum utilizam corect GetLastError?

Post by Ovidiu Cucu » 19 Aug 2011, 12:51

Intrebare
Cum utilizam corect GetLastError pentru a obtine codul de eroare dupa un apel de functie WinAPI?

Raspuns
  • In primul rand, aruncam un ochi in documentatie sa vedem daca functia data seteaza last-error code (valoarea care va fi returnata de GetLastError). Daca da, de obicei exista o referire la GetLastError in sectiunea "Return Values" (exemplu: "To get extended error information, call GetLastError").
  • Vedem ce valoare intoarce functia in caz de eroare. Poate fi zero, un handle NULL sau o alta valoare cum ar fi INVALID_HANDLE_VALUE.
  • In fine, testam in cod valoarea returnata iar in caz de eroare chemam GetLastError.
Exemple

Code: Select all

   BOOL bRet = ::DeleteFile(pszFileName);
   if(! bRet) // DeleteFile function has failed
   {
      DWORD dwError = ::GetLastError();
      // ...
   }

Code: Select all

   HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessID);
   if(NULL == hProcess) // OpenProcess function has failed
   {
      DWORD dwError = ::GetLastError();
      // ...
   }

Code: Select all

   HANDLE hFind = ::FindFirstFile(pszFileName, &findData);
   if(INVALID_HANDLE_VALUE == hFind) // FindFirstFile function has failed
   {
      DWORD dwError = ::GetLastError();
      // ...
   }
Note
  1. Nu toate functiile WinAPI seteaza pe zero last-error code in caz de succes.
    O greseala destul de frecventa pe care o fac programatorii este de a chema GetLastError fara ca mai inainte sa vada daca functia a esuat sau nu. In exemplul urmator, GetLastError intoarce valoarea 8 (ERROR_NOT_ENOUGH_MEMORY) chiar daca functia LoadImage a avut succes.

    Code: Select all

       HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, pszFileName,
          IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);
    
       DWORD dwError = ::GetLastError(); 
       // This is wrong! You have to call GetLastError only if hBitmap is NULL.
  2. Unele functii WinAPI (e.g. RegQueryValueEx) intorc direct codul de eroare deci nu mai are sens sa chemam GetLastError.
    In orice caz, trebuie mai intai de vazut in documentate daca o functie data seteaza last-error sau nu.
Vezi si



mesajflaviu
Membru++
Membru++
Posts: 684
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: [WinAPI] Cum utilizam corect GetLastError?

Post by mesajflaviu » 17 May 2013, 10:28

Ca o completare, rezultatul ::GetLastError se poate "traduce" in text in modul urmator:

Code: Select all

// MyFile.h

CString GetErrorString(const DWORD dwError);

Code: Select all

// MyFile.cpp

CString GetErrorString(const DWORD dwError)
{
    CString strError;
    LPTSTR lpszBuffer = NULL;
    if(0 == ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 
        NULL, dwError, 0, (LPTSTR)&lpszBuffer, 0, NULL))
    {  
        // FormatMessage failed
        strError.Format(_T("Unknown error: 0x%08X"), dwError);
    }
    else // success
    {      
        strError = lpszBuffer;
        strError.TrimRight(_T("\r\n")); // remove CRLF
        ::LocalFree(lpszBuffer);
    }
    return strError;
}
si un exemplu de folosire:

Code: Select all

	HBITMAP hBitmap = (HBITMAP)::LoadImage(NULL, lpszPathName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
	if(NULL == hBitmap)
	{
		CString sMessage;
		const DWORD dwError = ::GetLastError();
		sMessage.Format(_T("Failed to load '%s' file. Reason: %s\n"), lpszPathName, GetErrorString(dwError));
		AfxMessageBox(sMessage, NULL, MB_ICONERROR);
		return;
	}

Post Reply