2

How can I write contents of a CString instance to a file opened by CreateFile using WriteFile Win32 API function?

Please note MFC is not used, and CString is used by including "atlstr.h"

edit: Can just I do

WriteFile(handle, cstr, cstr.GetLength(), &dwWritten, NULL); 

or

WriteFile(handle, cstr, cstr.GetLength() * sizeof(TCHAR), &dwWritten, NULL); 

?

Hayri Uğur Koltuk
  • 2,970
  • 4
  • 31
  • 60
  • 1
    Text files have a specification. Which format do you want the resulting file? Who will use the file? You should probably not be writing TCHARs to a file; you should be explicit about the encoding (UTF-16, UTF-8, ANSI, ...). – tenfour Sep 21 '11 at 10:13
  • I will read the file using notepad. Format? just some lines one after another. I want to be able to open the file in notepad regardless of the encoding of project. Is it impossible or can I? – Hayri Uğur Koltuk Sep 21 '11 at 10:17
  • 1
    What encoding do you want to use? UTF16? UTF8? ANSI? – David Heffernan Sep 21 '11 at 13:05

5 Answers5

6

With ATL it's like this:

CString sValue;
CStringW sValueW(sValue); // NOTE: CT2CW() can be used instead

CAtlFile File;
ATLENSURE_SUCCEEDED(File.Create(sPath, GENERIC_WRITE, ...));
static const BYTE g_pnByteOrderMark[] = { 0xFF, 0xFE }; // UTF-16, Little Endian
ATLENSURE_SUCCEEDED(File.Write(g_pnByteOrderMark, sizeof g_pnByteOrderMark));
ATLENSURE_SUCCEEDED(File.Write(sValueW, (DWORD) (sValueW.GetLength() * sizeof (WCHAR))));

It's byte order mark (BOM) which lets Notepad know that encoding is UTF-16.

Roman R.
  • 68,205
  • 6
  • 94
  • 158
4

You need to pick a text encoding, convert the string to that encoding, and write the text file accordingly. Simplest is ANSI, so basically you would use the T2CA macro to convert your TCHAR string to ansi, then dump the contents in a file. Something like (untested/compiled):

// assumes handle is already opened in an empty new file
void DumpToANSIFile(const CString& str, HANDLE hFile)
{
    USES_CONVERSION;
    PCSTR ansi = T2CA(str);
    DWORD dwWritten;
    WriteFile(hFile, ansi, strlen(ansi) * sizeof(ansi[0]), &dwWritten, NULL);
}               

Because it's ANSI encoding though, it will only be readable on computers that have your same code page settings. For a more portable solution, use UTF-8 or UTF-16.

tenfour
  • 36,141
  • 15
  • 83
  • 142
2

Converting to ANSI can cause problems with code pages, so it is not acceptable in many cases. Here is a function that saves unicode string to unicode text file:

void WriteUnicodeStringToFile(const CString& str, LPCWSTR FileName)
{
HANDLE f = CreateFileW(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (f == INVALID_HANDLE_VALUE) return; //failed
DWORD wr;
unsigned char Header[2]; //unicode text file header
Header[0] = 0xFF;
Header[1] = 0xFE;
WriteFile(f, Header, 2, &wr, NULL);
WriteFile(f, (LPCTSTR)str, str.GetLength() * 2, &wr, NULL); 
CloseHandle(f);
}

Using:

CString str = L"This is a sample unicode string";
WriteUnicodeStringToFile(str, L"c:\\Sample.txt");

Notepad understands unicode text files.

Mike
  • 1,717
  • 2
  • 15
  • 19
1

I believe you need additional casting:

WriteFile(handle, (LPCVOID)(LPCTSTR)cstr, cstr.GetLength() * sizeof(TCHAR), &dwWritten, NULL);
Alex F
  • 42,307
  • 41
  • 144
  • 212
  • 1) If you have to put "I believe" in your answer, it's probably best to not answer. 2) Never cast to void* – tenfour Sep 21 '11 at 10:11
  • 1
    @tenfour: OK, I am sure, not only beleive. Regarding casting to void* - this is WriteFile parameter type. I beleive your post is not constructive... – Alex F Sep 21 '11 at 10:16
0

Also make sure that you write proper byte order mark in the beginning so that Notepad can read it properly.

Vishal
  • 1,199
  • 1
  • 8
  • 13