locked
ANSI file handling in 64-bit Windows with C++ RRS feed

  • Question

  • In trying to create ANSI file handling functions in 64-bit I've run across some problems...

    I don['t have any problems opening a file:

    HANDLE openbinaryfile(std::string namefile)
    {
         std::wstring wpath=strtowstr(namefile);
         DWORD daccess=GENERIC_READ | GENERIC_WRITE;
         return CreateFile(wpath.c_str(),daccess,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
    }

    But positioning to a byte position seems to be an issue,

    BOOL seek(HANDLE hfile,LONG bytepos)
    {
         return SetFilePointer(hfile,bytepos,NULL,FILE_BEGIN);
    }

    and so does reading a specific number of bytes from that location:

    std::string get$(HANDLE hfile,DWORD numbytes)
    {
         DWORD bytesread;
         LPBYTE lpb=new BYTE[numbytes];
         ReadFile(hfile,lpb,numbytes,&bytesread,NULL);
         std::string b=lpb;
         return b;
    }

    Any ideas?

    Friday, August 21, 2015 7:39 PM

Answers

  • You're supposed to use char, not unsigned char. And you've also changed the type of lpb from a pointer to an array, arrays can't have variable length so this won't work.

    Basically you need this:

    std::string get$(HANDLE hfile, DWORD numbytes)
    {
    	DWORD bytesread;
    	char *lpb = new char[numbytes];
    	ReadFile(hfile, lpb, numbytes, &bytesread, NULL);
    	std::string b { lpb, bytesread };
    	delete lpb;
    	return b;
    }
    

    Note that this initializes the string by using the constructor that takes a char* and a count of characters to be copied from that string. This deals with the lack of a terminating NUL character and with the fact that ReadFile might read less bytes than requested.

    It also takes care to delete the allocated array. There are better ways to do that but I did it like this to remind you that allocated memory must be freed when no longer needed.

    • Marked as answer by TallGuy63 Friday, August 21, 2015 8:29 PM
    Friday, August 21, 2015 8:13 PM

All replies

  • "In trying to create ANSI file handling functions in 64-bit I've run across some problems..."

    What does ANSI and 64 bit to do with your code?

    "But positioning to a byte position seems to be an issue,"

    What's the issue?

    "and so does reading a specific number of bytes from that location:"

    That function attempts to initialize a std::string from a BYTE*. That doesn't work because BYTE is actually "unsigned char" which is not the same thing as "char". Also, if you want to initialize a std::string from file data you better make sure that the data you read has a NUL character at the end, most likely it doesn't...

    Friday, August 21, 2015 7:54 PM
  • Doing it like this, I still can't get the unsigned char to a std::string

    std::string get$(HANDLE hfile,DWORD numbytes)
    {
         DWORD bytesread;
         unsigned char* lpb=new unsigned char[numbytes];
         ReadFile(hfile,lpb,numbytes,&bytesread,NULL);
         std::string b=lpb;  <- error
         return b;
    }


    As for the SEEK issue with pointing to bytepos is that it doesn't seem to point to the byte position in the file that I'm looking for.  I just want seek(hfile,10) to start reading at the 11th byte, etc...
    • Edited by TallGuy63 Friday, August 21, 2015 8:07 PM
    Friday, August 21, 2015 8:02 PM
  • You're supposed to use char, not unsigned char. And you've also changed the type of lpb from a pointer to an array, arrays can't have variable length so this won't work.

    Basically you need this:

    std::string get$(HANDLE hfile, DWORD numbytes)
    {
    	DWORD bytesread;
    	char *lpb = new char[numbytes];
    	ReadFile(hfile, lpb, numbytes, &bytesread, NULL);
    	std::string b { lpb, bytesread };
    	delete lpb;
    	return b;
    }
    

    Note that this initializes the string by using the constructor that takes a char* and a count of characters to be copied from that string. This deals with the lack of a terminating NUL character and with the fact that ReadFile might read less bytes than requested.

    It also takes care to delete the allocated array. There are better ways to do that but I did it like this to remind you that allocated memory must be freed when no longer needed.

    • Marked as answer by TallGuy63 Friday, August 21, 2015 8:29 PM
    Friday, August 21, 2015 8:13 PM
  • " I just want seek(hfile,10) to start reading at the 11th byte, etc..."

    Is there anything in that file? You opened it with CREATE_NEW...

    Friday, August 21, 2015 8:17 PM
  • Thanks Mike... i didn't know about the bracket assignment thing... never used it

    That took care of it.

    Friday, August 21, 2015 8:30 PM
  • "i didn't know about the bracket assignment thing"

    That's so called initialization syntax and in this case it's the same thing as "std::string b(lpb, bytesread);" which you may have seen before. The important thing here is the use of that particular constructor which avoids the need for a terminating NUL character.

    Friday, August 21, 2015 9:17 PM
  • Yea I got it. Thanks

    Friday, August 21, 2015 9:24 PM
  • On 21/08/2015 21:39, TallGuy63 wrote:

    std::string get$(HANDLE hfile,DWORD numbytes)
    {
          DWORD bytesread;
          LPBYTE lpb=new BYTE[numbytes];
          ReadFile(hfile,lpb,numbytes,&bytesread,NULL);
          std::string b=lpb;
          return b;
    }

    In addition to Mike Danes' post, note that you have a memory leak in this function, since you are allocating an array of BYTEs on the heap using new[], without delete[]ing it.

    You may want to use RAII-friendly techniques instead, like using std::vector to allocate the array, or a smart pointer like std::unique_ptr, etc. In this way, the allocated memory is automatically released when the function returns.

    Giovanni

    Monday, August 24, 2015 9:59 AM
  • Yes I added the delete to the function that day; there is no memory leak.

    Thanks

    Monday, August 24, 2015 1:40 PM
  • On 24/08/2015 15:40, TallGuy63 wrote:

    Yes I added the delete to the function that day; there is no memory leak.

    The best deletion/cleanup code is the one that you don't see, the one that is hidden, that is automatically invoked by the C++ compiler at the closing brace, thanks to RAII and destructors.

    Giovanni

    Tuesday, August 25, 2015 3:15 PM