Dire che un file "è Unicode" non vuol dire niente (di Unicode ci sono numerose codifiche, tra cui UTF-8, UTF-16 e UCS-4, le ultime due nelle varianti little endian e big endian e con e senza il BOM iniziale); inoltre, il fatto che _wfopen accetti un nome di file "wide", fgetws riempia un buffer di wchar_t e quello che è effettivamente l'encoding del file sono concetti ortogonali:
- fopen/_wfopen: l'unica differenza è che _fwopen accetta un nome file in caratteri wide, ovvero puoi aprire anche file con nomi "strani"; questo non impatta in alcuna maniera la modalità di lettura del file;
- fgets/fgetws: la differenza è che una riempie un buffer di caratteri "normali", una un buffer di caratteri "wide"; come avvenga la conversione dai byte del file a quello che viene messo nel buffer non è direttamente legato all'usare l'una o l'altra:
- se il file è aperto in modalità testo, la CRT cerca di effettuare una transcodifica del file "dietro le quinte", da "encoding del file" a "encoding del buffer target" ("encoding locale" nel caso di fgets, "UTF-16 LE" nel caso di fgetws); di default, fopen marca il file come in "encoding locale" (su macchine Windows italiane windows-1252), e se fai una fgetws di fatto vengono letti caratteri nell'encoding in questione e convertiti in caratteri wide; purtroppo, nel tuo caso questo comportamento non va bene, dato che il file non è in "encoding locale", ma con ogni probabilità è in UTF-16 LE (quello che notepad chiama "Unicode");
- se il file è aperto in modalità binaria, la CRT non si impiccia e legge direttamente dal file i codepoint UTF-16 (su Windows i wchar_t sono di 2 byte)
A questo punto, per risolvere questo problema hai due possibilità:
- puoi spiegare alla CRT che il tuo file non è in encoding locale, ma bensì in UTF-16; questo si può fare aggiungendo nella stringa di modo di apertura del file il parametro "ccs=UTF-16LE" (_wfopen(L"stampa.lst", L"r,ccs=UTF-16LE")); questo fa sì che quando leggi con la fgetws i byte del file vengano interpretati correttamente; incidentalmente, in questa maniera puoi anche usare la normale fgets se non ti interessano i caratteri non-locali (la CRT fa la transcodifica UTF-16=>encoding locale dietro le quinte);
- puoi dire alla CRT di farsi i cavoli suoi, e aprire il file in modalità binaria (_wfopen(L"stampa.lst", L"rb")); a questo punto, se il file è effettivamente in UTF-16 LE, puoi leggere senza problemi con la fgetws (ma non con la fgets - otterresti i byte "grezzi"); principale effetto collaterale: non viene rimosso automaticamente dal runtime il doppio terminatore di riga (in coda alle righe ti trovi \r\n invece del solo \n).
(incidentalmente, per quanto mi riguarda sono della scuola di pensiero che gli stream C sono il posto sbagliato dove "nascondere" conversioni di encoding e similari, sia perché il supporto ai vari encoding è malamente documentato, in una zona grigia tra lo standard e il non standard e molto variabile a seconda della piattaforma e delle configurazioni, sia perché la trasformazione "trasparente" dei dati del file "rompe" concettualmente diverse operazioni di libreria che nascono per lavorare sui byte grezzi - per dire, una fseek su un file aperto in modalità testo è rotta by design; quindi, se chiedi a me i file si aprono sempre in modalità binaria e se c'è da fare conversioni di encoding si usano librerie che danno qualche garanzia in più per quanto riguarda il supporto dei vari encoding - dalle API di Windows a Qt o a ICU)
Riferimenti:
https://msdn.microsoft.com/en-us/library/yeby3zcb.aspx
https://msdn.microsoft.com/en-us/library/c4cy2b8e.aspx
https://msdn.microsoft.com/en-us/library/c37dh6kf.aspx