I am trying to use WriteFile to write a simple text in a .TXT file. Here's my declaration:
// For WriteFile fuction
BOOL writeFile;
LPCVOID textToWrite = L"SakyLabs: Hello, MDE.";
DWORD numberOfBytes = (DWORD)wcslen(textToWrite);
DWORD numberOfBytesWritten;
numberOfBytes was based on Microsoft's example from here.
Next, the WriteFile function:
writeFile = WriteFile(createFile, textToWrite, numberOfBytes, &numberOfBytesWritten, NULL);
I am getting createFile from a previous CreateFileW call. Also, I am using Unicode functions.
WriteFile works, but I only get this part of the text written in the file:
S a k y L a b s : H
What am I doing wrong?
The problem is that you're creating a wide-charecter string L"...". Each WCHAR is two bytes long -- because Windows is using UTF-16 for wide strings. wcslen counts the number WCHARs in it rather than bytes.
Either multiply the string length by the size of a WCHAR:
DWORD numberOfBytes = (DWORD)wcslen(textToWrite)*sizeof(WCHAR);
or use narrow char strings (preferably UTF-8 encoded if you actually use non-ASCII):
LPCVOID textToWrite = "SakyLabs: Hello, MDE.";
DWORD numberOfBytes = (DWORD)strlen(textToWrite);
Related
Consider the following two functions, the first one uses the Windows API functions ReadFile() and CreateFileW(), whereas the second function uses fopen() and fgetws(), to read a non-English text from a file called data.txt.
The first function outputs garbage text, whereas the second function outputs the text from the file without any problems.
Notice that fopen() has ccs=UTF-8 that defines what character encoding to use, whereas read_file_2() does not have something similar.
DWORD read_file_2()
{
wchar_t wstr[512];
BOOL success = FALSE;
DWORD dwRead, total =0;
HANDLE handle = CreateFileW(L"data.txt",
GENERIC_READ,
0,
NULL,
3,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (handle == INVALID_HANDLE_VALUE)
return -1;
do
{
success = ReadFile(handle, wstr, 20, &dwRead, NULL);
total += dwRead;
} while(!success || dwRead == 0);
wstr[total] = L'\0';
wprintf(L"%ls\n",wstr);
return 0;
}
void read_file_1()
{
wchar_t converted[20];
FILE * ptr;view=msvc-170
ptr = fopen("data.txt", "rt+,ccs=UTF-8");
fgetws(converted, 20, ptr);
wprintf(L"%ls\n", converted);
fclose(ptr);
}
int main()
{
_setmode(fileno(stdin), _O_U8TEXT);
_setmode(fileno(stdout), _O_U8TEXT);
read_file_1();
read_file_2();
}
How does one use ReadFile() to read a wchar_t string from a text file and output it to the terminal without turning it into garbage text?
Шифрование.txt ال
퀠킨톸톄킀킾킲킰킽킸♥
Actual content of data.txt:
Шифрование.txt العربية.txt
You can use MultiByteToWideChar.
int total_wchars = MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
bytes, // lpMultiByteStr The bytes read using `ReadFile`/`read`.
total_bytes, // cbMultiByte No need for NUL.
NULL, // lpWideCharStr
0 // cchWideChar 0 = Get size incl NUL.
);
if ( total_wchars == 0 ) {
// Error. Use GetLastError() and such.
...
}
LPWSTR wchars = malloc( total_wchars * sizeof( *wchars ) );
MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
bytes, // lpMultiByteStr
total_bytes, // cbMultiByte
wchars, // lpWideCharStr
total_wchars // cchWideChar
);
Note that if the compiler has wchar_t,
WCHAR is wchar_t
LPWSTR is wchar_t *
LPCWSTR is const wchar_t *
The problem is that ReadFile() doesn't read strings, or even characters. It reads bytes.
Since it doesn't read strings, it also doesn't null-terminate the data like a string.
You need to make sure that it reads enough bytes, and to null-terminate the buffer if it's a string.
By using a loop, you have a good start, but your loop overwrites what was read in the last iteration of the loop, making you lose the data.
You need to pass a pointer to the end of the buffer in the loop.
And as I already mentioned in a comment, make sure that the loop works properly (and not go into an infinite loop if there's an error, for example).
I've got a C project that I'm working on and I'm having a problem.
The program reads a string that is echoed by a .php page. It uses this code
to read the data and appoint it to a variable, which get sent to the Commands() function:
LPSTR szBuffer=(LPSTR)chunk+0x1000;
DWORD dwRead;
if (CWA(_HttpSendRequestA, wininet, hHttpRequest, szHeaders, lpstrlenA(szHeaders), szReq, lpstrlenA(szReq)) != 0)
{
CWA(_InternetReadFileA, wininet, hHttpRequest, szBuffer, 0x400, &dwRead);
if (dwRead)
Commands((LPBYTE)szBuffer, dwRead);
}
As you can see the data is sent to the Commands() function, which receives the LPBYTE szBuffer (named "command" in the function) and the DWORD dwRead (named "size" in the function).
In the Commands() function, it's supposed to read the string that it read from the .php page. However, since the data seems to be stored as LPBYTE, I've done a lot of things trying to get that to a char*. When I thought I had finally got it however, I tried outputting it using a MessageBox (to see if it displays the string it should have read). However, this returns me Chinese characters (while the original string should be this:
"TASKci=0C73CCFD206BBD011E7087CE0806E6F6E69630,job=dlex,ti=AD62A5950B76F3812C542C24040EACE9,pr=https,ur=//test.com/test.txt,cl=".
Screenshot of what it returns me: http://prntscr.com/h0p5iw
How the code inside Commands() looks:
BOOL Commands(LPBYTE command, DWORD size) {
LPTSTR x = (LPTSTR)((char*)command);
{
int msgboxID = MessageBox(
NULL,
x,
(LPCWSTR)L"Woop",
MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2 );
}
CWA(Sleep, kernel32, 100);
return 1; }
I'm new at C (I've only written stuff in C# before) so I am sorry if I am asking any dumb questions, I've really tried my best but I cannot seem to find any solution by myself.
Also, keep in mind that everything except for the stuff inside the Commands() function is not coded by me but by someone who is way more experienced. That code should be fine and I am sure that it is reading the data from the page, it's probably just me screwing up a conversion somewhere.
A narrow string (char*) tends to look like Chinese when you use it somewhere that expects a wide UTF-16 Unicode string.
You cannot just cast the string to change its type, you need to call MultiByteToWideChar.
This question already has answers here:
How do I concatenate const/literal strings in C?
(17 answers)
Closed 6 years ago.
I want to add an string to a LPTSTR.
The code is:
hSourceFile = CreateFile(
pszSourceFile,
FILE_READ_DATA,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE != hSourceFile)
{
_tprintf(
TEXT("The source plaintext file, %s, is open. \n"),
pszSourceFile);
}
The pszSourceFile is a type of LPTSTR, but i want to add some extra text.
Like (not working)
pszSourceFile + ".txt"
What is the best way to do this?
Considering the C-style and the use of the Windows API (with TEXT() et. al.); use _tcscat() or _tcsncat() (the later requires a buffer size).
For example;
TCHAR buffer[1024] = {}; // or '\0'
_tcsncat(buffer, pszSourceFile, 1024);
_tcsncat(buffer, TEXT(".txt"), 1024);
Demo.
Warning; watch out for your buffer overruns. Assuming the "normal" Windows 260 character path file and name limits (_MAX_PATH), the buffer needs to cater for that.
For C++ (as originally tagged), an alternative is to use std::basic_string<TCHAR> and then the operator+ (or +=) as per usual. The .c_str() will get you the resultant string;
std::basic_string<TCHAR> buffer(pszSourceFile);
buffer += TEXT(".txt");
auto ptr = buffer.c_str();
Your particular use case is not a simple "append" but rather an insert/format. Along the same lines as Niall you are using the TCHAR macros so I would recommend _stprintf_s (or _sntprintf_s... see MSDN)
TCHAR output[SIZE] = {0};
_stprintf_s(output, _T("The %s directory"), pszSourceFile);
Of course it depends on what exactly pszSourceFile is... if it is a std::string then you'll need to use the c_str() member to get a pointer, and you'll need to be careful about using std::string versus std::wstring.
I'm porting some C code that loads sprites from files containing multiple bitmaps. Basically the code fopens the file, fgetcs some header info, then freads the bitmap data. I can see that the fgetcs are returning proper data, but the outcome of the fread is null. Here's the code - fname does exist, the path is correct, fil is non-zero, num is the number of sprites in the file (encoded into the header, little-endian), pak is an array of sprites, sprite is a typedef of width, height and bits, and new_sprite inits one for you.
FILE *fil;
uint8 *buffu;
uint8 read;
int32 x,num;
int32 w,h,c;
fil = fopen(fname, "rb");
if (!fil) return NULL;
num = fgetc(fil);
num += fgetc(fil)*256;
if (num > max) max = num;
for (x=0;x<max;x++) {
// header
w=fgetc(fil);
w+=fgetc(fil)*256;
h=fgetc(fil);
h+=fgetc(fil)*256;
fgetc(fil); // stuff we don't use
fgetc(fil);
fgetc(fil);
fgetc(fil);
// body
buffu = (uint8*)malloc(w * h);
read=fread(buffu,1,w*h,fil);
pak->spr[x]=new_sprite(w,h);
memcpy(pak->spr[x]->data, buffu, w*h);
// done
free(buffu);
}
I've stepped through this code line by line, and I can see that w and h are getting set up properly, and read=4096, which is the right number of bits. However, buffer is "" after the fread, so of course memcpy does nothing useful and my pak is filled with empty sprites.
My apologies for what is surely a totally noob question, but I normally use Cocoa so this pure-C file handling is new to me. I looked all over for examples of fread, and they all look like the one here - which apparently works fine on Win32.
Since fgetc seems to work, you could try this as a test
int each;
int byte;
//body
buffu = malloc(w * h);
for (each = 0; each < w*h; each++) {
byte = fgetc(fil);
if ( byte == EOF) {
printf("End of file\n");
break;
}
buffu[each] = (uint8)byte;
printf ("byte: %d each: %d\n", byte, each);
}
pak->spr[x]=new_sprite(w,h);
memcpy(pak->spr[x]->data, buffu, w*h);
// done
You say:
However, buffer is "" after the fread, so of course memcpy does nothing useful
But that is not true at all. memcpy() is not a string function, it will copy the requested number of bytes. Every time. If that isn't "useful", then something else is wrong.
Your buffer, when treated as a string (which it is not, it's a bunch of binary data) will look like an empty string if the first byte happens to be 0. The remaining 4095 bytes can be whatever, to C's string printing functions it will look "empty".
I'm trying to write a wchar array to a file in C, however there is some sort of corruption and unrelevant data like variables and paths like this
c.:.\.p.r.o.g.r.a.m. .f.i.l.e.s.\.m.i.c.r.o.s.o.f.t. .v.i.s.u.a.l. .s.t.u.d.i.o. 1.0...0.\.v.c.\.i.n.c.l.u.d.e.\.x.s.t.r.i.n.g..l.i.s.t...i.n.s.e.r.t
are written on to the file along with the correct data (example) I have confirmed that the buffer is null-terminated and contains proper data.
Heres my code:
myfile = fopen("logs.txt","ab+");
fseek(myfile,0,SEEK_END);
long int size = ftell(myfile);
fseek(myfile,0,SEEK_SET);
if (size == 0)
{
wchar_t bom_mark = 0xFFFE;
size_t written = fwrite(&bom_mark,sizeof(wchar_t),1,myfile);
}
// in another func
while (true)
{
[..]
unsigned char Temp[512];
iBytesRcvd = recv(sclient_socket,(char*)&Temp,iSize,NULL);
if(iBytesRcvd > 0 )
{
WCHAR* unicode_recv = (WCHAR*)&Temp;
fwrite(unicode_recv,sizeof(WCHAR),wcslen(unicode_recv),myfile);
fflush(myfile);
}
[..]
}
What could be causing this?
recv() will not null-terminate &Temp, so wcslen() runs over the bytes actually written by recv(). You will get correct results if you just use iBytesReceived as byte count for fwrite() instead of using wcslen() and hoping the data received is correctly null-terminated (wide-NULL-terminated, that is):
fwrite(unicode_recv, 1, iBytesReceived, myfile);