Sign in to follow this  

readFile and LPVOID

This topic is 4687 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I believe alot of my binary I/O headaches can be solved using microsoft's readFile function. I have a few questions, though, if anyone has any experience using it. First of all, what, exactly, is an LPVOID type? I can't really find anything about it on google or MSDN. I know it's a like a pointer to the buffer the memory will be stored in when readFile is called, but how am I to access the data? Can I just go to whatever byte I want and just read in and cast the data however I chose? So like if I know there are 4 bytes of float at bytes 80, 84, and 88 can I just do:
float one, two, three;
one = float(lpBuffer[80]);
two = float(lpBuffer[84]);
three = float(lpBuffer[88]);

And will the compiler know how to take the 4 binary bytes and convert them to a float? Or do I access the data some other way?

Share this post


Link to post
Share on other sites
Ok, I've done a little more research. This function is actually pretty cool. I have another question, though. The prototype for the readFile function is as follows:


BOOL ReadFile(
HANDLE hFile, // handle of file to read
LPVOID lpBuffer, // address of buffer that receives data
DWORD nNumberOfBytesToRead, // number of bytes to read
LPDWORD lpNumberOfBytesRead, // address of number of bytes read
LPOVERLAPPED lpOverlapped // address of structure for data
);



That has almost everything I need. I specify the handle to the file to be read, the buffer to store what is read into, the number of bytes to read...what I'm missing, though, is how to specify where reading should begin. I'd like to use the function in the middle of a loop. The data I'm reading has an 80 byte header and then any number of blocks of data following. So I'd like to read in that 80 byte buffer, enter the loop, read in the block of data, and then loop if I'm not at the end of the file. But it appears as though there's no pointer to track where I've read from so far. So it looks as though every time the ReadFile function is called, it starts from the beginning. Say it isn't so...

Share this post


Link to post
Share on other sites
It starts from where it last finished. Use SetFilePointer(Ex) to seek forwards, backwards, or to a specific byte.

LPVOID = void *. It has no idea of what data it holds, and thus, cannot be indexed. You can do this though.

*((float*)&((char*)myvoidptr)[mybyteoffset]);
(ie: convert to char *, offset it in bytes, convert to float *, then dereference it to get the actual float).

Share this post


Link to post
Share on other sites
Wow, that's quite a bit of casting. This article I found here on file i/o declares an array of DWORDs and just passes that in as the lpBuffer parameter. Can I not just do something similar with floats?

Here's the article:
http://www.gamedev.net/reference/articles/article707.asp

Share this post


Link to post
Share on other sites
Thanks for everyone's help so far. I've written the preliminary version of my function just to see if everything I've learned so far is working. It appeared to have worked the very first time it was run. The screen opened and it was outputting what appeared to be proper values, but it closed immediately (on a side note does anyone know how I can disable that in MSVS.net) so I really didn't get a chance to check anything. I ran it again to see if it was really working and this time nothing read successfully. The first two ReadFile calls returned false, and it hangs at that point.

I am lead to believe I am clobbering something on accident. I can't really check to see if the file has been corrupted (as it is binary), but it's still the same size as before. Can someone see if I'm doing something illegal:


void loadListBin()
{
Vector normVector;
Vector tempVector;
float float1, float2, float3;
char header[80];
float *buffer;
HANDLE hFile;
DWORD numRead = 0;
bool readSuccess;
int *numFacets = new int;

hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

readSuccess = ReadFile(hFile, header, sizeof(char) * 80, &numRead, NULL);
cout << "readSuccess = " << readSuccess << endl;
cout << "numRead = " << numRead << endl << endl;

readSuccess = ReadFile(hFile, numFacets, sizeof(int), &numRead, NULL);
cout << "readSuccess = " << readSuccess << endl;
cout << "header = " << header << endl;
cout << "number of facets = " << *numFacets << endl << endl;
buffer = new float[*numFacets];

readSuccess = ReadFile(hFile, buffer, sizeof(float) * *numFacets, &numRead, NULL);
cout << "readSuccess = " << readSuccess << endl;
cout << "numRead = " << numRead << endl << endl;

cout << "Normal 1 = " << buffer[0] << endl;
cout << "Normal 1 = " << buffer[4] << endl;
cout << "Normal 1 = " << buffer[8] << endl;

cout << "Vertex 1 = " << buffer[12] << endl;
cout << "Vertex 1 = " << buffer[14] << endl;
cout << "Vertex 1 = " << buffer[16] << endl;

delete [] buffer;
delete numFacets;
CloseHandle(hFile);
}





I delete my buffers and close the file...what have I missed?

EDIT: Perhaps I have to inform the file it will be reading binary? Or will it take care of that on its own?

[Edited by - CyberSlag5k on February 11, 2005 10:17:23 AM]

Share this post


Link to post
Share on other sites
You never check that CreateFile() returns a valid handle. It'll return INVALID_HANDLE_VALUE if it can't open the file.
Aside from that, the code seems to work for me. Are you sure the file contains the correct data?

Also, you don't need this: int *numFacets = new int;. You can just do int numFacets;, and pass the address of the variable to ReadFile.

I usually prevent the console application from closing immediately by putting a breakpoint on the last line of main(). Or you could put an assert(false);, and include assert.h, or you could include process.h and do system("pause");.
If you want a proper way to do it, that'll work erliably in release mode as well as debug mode, you need to read data from cin and wait for the user to hit enter.

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
You never check that CreateFile() returns a valid handle. It'll return INVALID_HANDLE_VALUE if it can't open the file.
Aside from that, the code seems to work for me. Are you sure the file contains the correct data?


Haha, silly mistake on my part. I had a space in between the file name and the extension so it wasn't getting the file correctly. I added that check in there which helped me identify the problem. Thanks.

Quote:

Also, you don't need this: int *numFacets = new int;. You can just do int numFacets;, and pass the address of the variable to ReadFile.


Good call.

Quote:

I usually prevent the console application from closing immediately by putting a breakpoint on the last line of main(). Or you could put an assert(false);, and include assert.h, or you could include process.h and do system("pause");.
If you want a proper way to do it, that'll work erliably in release mode as well as debug mode, you need to read data from cin and wait for the user to hit enter.


Yeah that's what I have been doing.


Great, so everything appears to be working properly (for now). Thanks a ton guys :).

Share this post


Link to post
Share on other sites
Correction, all is not well. Should I have casted something differently? Some of my values are quite screwy:

<-5.59009e-033, -5.01574e+018, -1.#QNAN>
<4.03392e+018, 6.07491e-039, 41.6217>
<6.96617e-017, 3.15394e-008, 1.62267e+032>
<-5.01574e+018, -1.#QNAN, 4.03392e+018>
<6.07491e-039, 41.6217, 6.96617e-017>
<3.15394e-008, 1.62267e+032, 1.15072e-040>
<-1.#QNAN, 4.03392e+018, 6.07491e-039>
<41.6217, 6.96617e-017, 3.15394e-008>
<1.62267e+032, 1.15072e-040, 1.03773e-026>
<4.03392e+018, 6.07491e-039, 41.6217>
<6.96617e-017, 3.15394e-008, 1.62267e+032>

I've never even seen #QNAN before, and the e###'s make me a little concerned. Plus, none of these values should be negative (although sometimes certain exporters break that convention. Does the e stuff suggest I should be using doubles? I think I might anyway, just to be safe. So yeah, these values are garbage, I think, but the rest of my stuff reads in ok.

Here's the new routine for processing the buffer data:


readSuccess = ReadFile(hFile, buffer, sizeof(float) * numFacets, &numRead, NULL);
if(readSuccess == false)
exit(456);

for(int i = 0; i < numFacets; i++)
{
normVector.setVector(buffer[0 + (i*4)], buffer[4 + (i*4)], buffer[8 + (i*4)]);
normalList.InsertItem(normVector);

tempVector.setVector(buffer[12 + (i*4)], buffer[16 + (i*4)], buffer[20 + (i*4)]);
vertexList.InsertItem(tempVector);

tempVector.setVector(buffer[24 + (i*4)], buffer[28 + (i*4)], buffer[32 + (i*4)]);
vertexList.InsertItem(tempVector);

tempVector.setVector(buffer[36 + (i*4)], buffer[40 + (i*4)], buffer[44 + (i*4)]);
vertexList.InsertItem(tempVector);
}





EDIT: It would be nice to be able to check my data to see what the values should actually be. I've tried a few hex viewers I found on download.com but they just came up gibberish. Anyone know a good (free) application for viewing binary files? The data is stored as floats, if that makes any difference.

[Edited by - CyberSlag5k on February 11, 2005 1:26:48 PM]

Share this post


Link to post
Share on other sites
Another question, is there a maximum size for these things? I have some pretty gigantic files. Since I'm dynamically allocating the buffer/array of floats, I should be able to load in files until I run out of available program memory, right?

Share this post


Link to post
Share on other sites
Quote:
Original post by CyberSlag5k
I've never even seen #QNAN before, and the e###'s make me a little concerned. Plus, none of these values should be negative (although sometimes certain exporters break that convention. Does the e stuff suggest I should be using doubles? I think I might anyway, just to be safe. So yeah, these values are garbage, I think, but the rest of my stuff reads in ok.

#QNAN means that the data read in doesn't represent a floating point number (NAN == Not A Number). The e### stuff is nothing to worry about. If you do float f = 10000000.0f; and then try to cout it, you'll get something with an exponent most likely.

Quote:
Original post by CyberSlag5k
normVector.setVector(buffer[0 + (i*4)], buffer[4 + (i*4)], buffer[8 + (i*4)]);

If buffer is an array of floats, then you should be adding 1 each time, not 4. The number is the index in "units" (floats in this case), not bytes (unless buffer is an array of bytes of course).
So, if buffer is an array of floats, the line should be: normVector.setVector(buffer[0 + (i*4)], buffer[1 + (i*4)], buffer[2 + (i*4)]); and similarly for the other lines (3+(i*4), etc).

Quote:
Original post by CyberSlag5k
EDIT: It would be nice to be able to check my data to see what the values should actually be. I've tried a few hex viewers I found on download.com but they just came up gibberish. Anyone know a good (free) application for viewing binary files? The data is stored as floats, if that makes any difference.

I use AXE quite happily.

Quote:
Original post by CyberSlag5k
Another question, is there a maximum size for these things? I have some pretty gigantic files. Since I'm dynamically creating the buffer/array of floats, I should be able to load in files until I run out of available memory, right?

There's not really any maximum size, But you'll have extreme problems going over 1Gb or so. I've allocated 700Mb in one go before (I have 512Mb RAM). It works, but the call to new takes 2 or 3 minutes (litterally).

Share this post


Link to post
Share on other sites
As always, Evil Steve, you are the man. Thank you.

I have noticed two more problems with my program. The first is that the data stream contains 2 bytes of nothing I have to skip (which I'm not). The second is that I am totally not going through the data correctly.

Assuming a float is 4 bytes (which on my system it is), look at the first setVector call. On the first iteration, we're reading in data elements 0 (0 + 0 * 4), 1 (1 + 0 * 4), and 2 (2 + 0 * 4). The last vector element set will be 11 (11 + 0 * 4). Now, on the second iteration the first setVector call will be elements 4 (0 + 1 * 4), 5 (1 + 1 * 4), and 6 (2 + 1 * 4). Silly me. I'm fixing it now (I can handle that on my own, I just wanted to point it out just in case anyone is doing anything similar).

Thanks again Evil Steve.

Share this post


Link to post
Share on other sites

This topic is 4687 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this