To do what you are trying to do “Right”, there are a few non-trivial things you need to consider. I will do my best to break them down for you here.
We start by defining the count parameter from the documentation for the wcstombs() function on MSDN :
The maximum number of bytes that can be stored in a multibyte output string.
Note that this does NOT say anything about the number of wide characters in the wide character input line. Despite the fact that all wide characters in the input line of your example ("New Text File.txt") can be represented as single-byte ASCII characters, we cannot assume that each wide character in the input string will generate exactly one byte in the output string for every possible input line (if this expression confuses you, you should check Joel's article on Unicode and character sets ). So, if you pass wcstombs() size of the output buffer, how does it know how long the input line is being entered? The documentation states that it is expected that the input string will be terminated with a null character in accordance with the standard C language convention:
If wcstombs encounters a character with a wide character (L '\ 0') before or when counting occurs, it converts it to 8-bit 0 and stops.
Although this is not explicitly stated in the documentation, we can conclude that if the input string does not end with zero, wcstombs() will continue to read wide characters until it writes count bytes to the output string. Therefore, if you are dealing with a large string of characters that does not end with zero, it is not enough just to know how long the input string is entered; you need to somehow know exactly how many bytes the output string should output (which cannot be determined without performing the conversion) and pass this as the count parameter to make wcstombs() do what you want.
Why am I focusing so much on this zero-termination issue? Since the structural documentation FILE_NOTIFY_INFORMATION on MSDN has this to say about its FileName field:
A variable-length field containing the file name relative to the directory descriptor. The file name is in Unicode character format and does not have a zero ending.
The fact that the FileName field does not have a zero end explains why it has a bunch of "unknown Chinese letters" at the end of it when you look at it in the debugger. The structural documentation FILE_NOTIFY_INFORMATION also contains another nugget of wisdom regarding the FileNameLength field:
The size of the part of the record file name in bytes.
Note that this says bytes, not characters. Therefore, even if you want to assume that each wide character in the input string generates exactly one byte in the output string, you should not pass fileInfo.FileNameLength for count ; you must go through fileInfo.FileNameLength / sizeof(WCHAR) (or use an input line with zero completion, of course). Combining all this information, we can finally understand why your initial wcstombs() call did not work: he read the end of the end and was choking on invalid data (thereby causing an EILSEQ error).
Now that we've figured out the problem, it's time to talk about a possible solution. In order to do it right, the first thing you need to know is how big your output buffer should be. Fortunately, the documentation for wcstombs() has one last tidbit that will help us here:
If mbstr is NULL, wcstombs returns the desired size in bytes of the target string.
So the idiomatic way of using the wcstombs() function is to call it twice: the first time to determine how large your output buffer should be, and the second time to actually do the conversion. The last thing we noted is that, as we stated earlier, the wide character input line must be terminated with a null character, at least for the first call to wcstombs() .
Putting it all together, here is a piece of code that does what you are trying to do:
size_t fileNameLengthInWChars = fileInfo.FileNameLength / sizeof(WCHAR); //get the length of the filename in characters WCHAR *pwNullTerminatedFileName = new WCHAR[fileNameLengthInWChars + 1]; //allocate an intermediate buffer to hold a null-terminated version of fileInfo.FileName; +1 for null terminator wcsncpy(pwNullTerminatedFileName, fileInfo.FileName, fileNameLengthInWChars); //copy the filename into a the intermediate buffer pwNullTerminatedFileName[fileNameLengthInWChars] = L'\0'; //null terminate the new buffer size_t fileNameLengthInChars = wcstombs(NULL, pwNullTerminatedFileName, 0); //first call to wcstombs() determines how long the output buffer needs to be char *pFileName = new char[fileNameLengthInChars + 1]; //allocate the final output buffer; +1 to leave room for null terminator wcstombs(pFileName, pwNullTerminatedFileName, fileNameLengthInChars + 1); //finally do the conversion!
Of course, be sure to call delete[] pwNullTerminatedFileName and delete[] pFileName when you are done with them to clear.
ONE LAST
After writing this answer, I re-read your question a little closer and thought about another mistake you might make. You say that wcstombs() fails after a simple conversion of the first two letters ("Ne"), which means that it strikes uninitialized data in the input line after the first two wide characters. Have you accidentally used an assignment operator to copy one FILE_NOTIFY_INFORMATION variable to another? For instance,
FILE_NOTIFY_INFORMATION fileInfo = someOtherFileInfo;
If you do this, it will only copy the first two large characters from someOtherFileInfo.FileName to fileInfo.FileName . To understand why this is the case, consider the declaration of the FILE_NOTIFY_INFORMATION structure:
typedef struct _FILE_NOTIFY_INFORMATION { DWORD NextEntryOffset; DWORD Action; DWORD FileNameLength; WCHAR FileName[1]; } FILE_NOTIFY_INFORMATION, *PFILE_NOTIFY_INFORMATION;
When the compiler generates code for an assignment operation, it does not understand the cheat that extends with FileName , which is a variable-length field, so it just copies sizeof(FILE_NOTIFY_INFORMATION) bytes from someOtherFileInfo to fileInfo , since FileName declared as an array from one WCHAR , you might think that only one character will be copied, but the compiler puts the structure another two bytes in length (so its length is an integer multiple of int ), so the second WCHAR .