2011-11-19 11 views
11

Oto program "Hello World", który wykorzystuje WINAPI za WriteFile (skompilowany w programie Microsoft Visual C++ 2008 Express):Dlaczego WriteFile ulega awarii podczas zapisu na standardowe wyjście?

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    wchar_t str[] = L"Hello world"; 

    HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); 
    if(out && out!=INVALID_HANDLE_VALUE) 
    { 
     WriteFile(out, str, sizeof(str), NULL, NULL); 
     CloseHandle(out); 
    } 

    return 0; 
} 

Jeśli wykonywane w oknie konsoli, to radośnie wita świat. Jeśli próbujesz przekierować standardowe wyjście, jednak, jak w

wypadków
hello.exe > output.txt 

programu w WriteFile (null pointer wyjątków). Mimo to plik output.txt istnieje i zawiera poprawne dane wyjściowe w całości.

Wezwanie stos o katastrofie:

[email protected]() + 0x75 bytes  
[email protected]() + 0x4e bytes  
srgprc2.exe!wmain(int argc=1, wchar_t * * argv=0x00483d88) Line 15 + 0x16 bytes C++ 

komunikat: "wyjątek Unhandled na 0x75ce85ea (KernelBase.dll) w srgprc2.exe: 0xC0000005. Naruszenie zasad dostępu lokalizacja pisanie 0x00000000"

Co tu się dzieje? Dzięki!

+3

Usuń wywołanie CloseHandle(). –

+0

... tak jak powinno być jasne, ponieważ używasz funkcji 'Get ...', a nie 'Open ...'. –

+0

The CloseHandle nie jest nawet wywoływana, awaria odbywa się w WriteFile i program się kończy. – user38329

Odpowiedz

17

Czwarty parametr do WriteFileis not optional. Przekazujesz NULL, co nie jest dozwolone.

+3

D'OH! "Ten parametr może mieć wartość NULL tylko wtedy, gdy parametr lpOverlapped nie ma wartości NULL". http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747%28v=vs.85%29.aspx – Mordachai

+0

Dziękuję. "__out_opt" w prototypie zdezorientowało mnie. – user38329

+0

Mam również ten sam problem, co OP wymienione w pytaniu. O ile pamiętam, przekazałem również NULL dla tego parametru. Więc ... Dzięki za wspaniałą odpowiedź. i tak ... +1 :) –

0

4-ty parametr (który mówi nam, jak wiele bajtów były faktycznie napisany) spodziewa się wskaźnik do wartości DWORD (aka unsigned int) Po przejechaniu NULL dla tego parametru to próbuje napisać DWORD null pointer co powoduje wyjątek, nie tylko przekazanie wskaźnika do tego argumentu jest obowiązkowe, ale powinieneś zawsze sprawdzić jego wartość po zapisie, ponieważ istnieje prawdopodobieństwo, że WriteFile zapisze mniej danych niż podałeś.