So, I'm trying to setup basic OpenGL scene using only Win32 API and OpenGL, but I've big problems with loading shaders and glShaderSource function. I'm reading my file like this:
//HEADER
class FileReader
{
public:
FileReader(const LPCSTR FileName);
const void* GetFileData();
~FileReader();
private:
HANDLE FileHandle;
void* FileDataMemory;
};
//ACTUAL CODE
FileReader::FileReader(const LPCSTR FileName)
{
FileHandle = CreateFileA(FileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (FileHandle == INVALID_HANDLE_VALUE)
{
OutputDebugStringA("Failed to open file ");
OutputDebugStringA(FileName);
OutputDebugStringA(" for reading, application could not be loaded\n");
ExitProcess(-2);
}
unsigned int FileSize = GetFileSize(FileHandle, 0);
DWORD BytesRead;
FileDataMemory = VirtualAlloc(0, FileSize, MEM_COMMIT, PAGE_READWRITE);
ReadFile(FileHandle, FileDataMemory, FileSize, &BytesRead, 0);
if (BytesRead < FileSize)
{
OutputDebugStringA("File was not read completely\n");
}
}
const void* FileReader::GetFileData()
{
return FileDataMemory;
}
FileReader::~FileReader()
{
CloseHandle(FileHandle);
}
And I use this class to load vertex shader from disc like this:
VertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(VertexShader, 1, static_cast<const GLchar* const*>(VertexShaderFile->GetFileData()), 0);
But my app gives me an access violation reading address 0xFFFFFFFF on line with glShaderSource. And I'm just so confused, because when I try to see this block of memory in debug mode, it looks properly and has correct data insisde it, so I just don't know what to do.
The shader source code string, which is read form the file is not 0 terminated.
Reserve FileSize+1 bytes of memory and ensure that the last byte of the buffer is 0. e.g.:
FileDataMemory = VirtualAlloc(0, FileSize+1, MEM_COMMIT, PAGE_READWRITE);
ZeroMemory(FileDataMemory, FileSize+1);
ReadFile(FileHandle, FileDataMemory, FileSize, &BytesRead, 0);
Further, the 3rd parameter to glShaderSource is an array of strings (const GLchar **):
const GLchar *source = static_cast<const GLchar*>(VertexShaderFile->GetFileData());
glShaderSource(VertexShader, 1, &source, 0);
What you actually do in your code is to cast VertexShaderFile->GetFileData(). What you would have to do ist to cast &VertexShaderFile->GetFileData()
Furthermore, I recommend to use STL to read the shader source file. e.g:
std::ifstream sourceFile(FileName, std::fstream::in);
std::string sourceCode = std::string(
std::istreambuf_iterator<char>(sourceFile),
std::istreambuf_iterator<char>());
Related
This function should read string from file and return it, but immediately after call to ReadFile program hits breakpoint in debug_heap.cpp file at line 985.
char* readFile()
{
char curDirectory[MAX_PATH];
GetCurrentDirectory(MAX_PATH, curDirectory);
char filePath[MAX_PATH];
char *name = "\\data.txt";
sprintf_s(filePath, "%s%s", curDirectory, name);
HANDLE hFile = CreateFile(filePath, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
DisplayError("Can't Create File");
return NULL;
}
DWORD fileSize = GetFileSize(hFile, NULL);
char *buffer = new char[fileSize / 2 + 1];
DWORD bytesReaded;
if (ReadFile(hFile, buffer, fileSize, &bytesReaded, NULL) == 0)
{
DisplayError("Can't read File");
return NULL;
}
buffer[bytesReaded] = '\0';
CloseHandle(hFile);
return buffer;
}
This is because your code writes beyond the end of buffer. You allocate buffer like this:
char *buffer = new char[fileSize / 2 + 1];
But then you attempt to read fileSize bytes from the file. Your allocation should instead be:
char *buffer = new char[fileSize + 1];
Some other comments:
Your call to sprintf_s risks buffer overrun.
Since you code in C++, use std::string and have that class manage buffers. You should do that for both filePath and buffer. That will allow you to avoid the leaks that your current code has. For instance, the failure return after ReadFile leaks memory. And it avoids placing a burden on the calling code to deallocate the memory.
You also leak the file handle if your code takes the failure return after ReadFile.
bytesReaded should be named bytesRead, to use the correct English word.
There is no real reason to believe that the executable file is located in the current working directory.
I am trying to write the content of unsigned short and unsigned char array content to an .img file. I am using WriteFile method to do the same. it seems like WriteFile function successfully writing the array content to the file but the main problem is i am not able to view that file in file system. Following are the two methods I am using to Write the data to the file.
void createImageFile(unsigned short* src,int srcLength,const char* fileName)
{
DWORD dwBytesWritten = 0;
unsigned short *dest = new unsigned short[srcLength];
if(is_file_exist(fileName))
{
remove(fileName);
}
HANDLE hFile = CreateFile(LPCWSTR(fileName), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD e = GetLastError();
if(hFile)
{
memcpy(dest,src,srcLength*sizeof(unsigned short));
bool b = WriteFile(hFile,dest,srcLength,&dwBytesWritten,NULL);
if(!b)
{
DWORD e = GetLastError();
} CloseHandle(hFile);
}
if(dest)
{
delete[] dest;
dest = NULL;
}
}
void createImageFile(unsigned char* src,int srcLength,const char* fileName)
{
DWORD dwBytesWritten = 0;
unsigned short *dest = new unsigned short[srcLength];
if(is_file_exist(fileName))
{
remove(fileName);
}
HANDLE hFile = CreateFile(LPCWSTR(fileName), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD e = GetLastError();
if(hFile)
{
memcpy(dest,src,srcLength*sizeof(unsigned short));
bool b = WriteFile(hFile,dest,srcLength,&dwBytesWritten,NULL);
if(!b)
{
DWORD e = GetLastError();
} CloseHandle(hFile);
}
if(dest)
{
delete[] dest;
dest = NULL;
}
}
I am not sure what exactly I am doing wrong. I am not able to view those files on the specified path. Can somebody please help me in this?
Another thing I want to highlight is, the above code is the part of unmanaged code and supposed to be reside in the dll.
You cannot just cast fileName to a wide string.
Don't forget to close the file.
CreateFile returns INVALID_HANDLE_VALUE not zero on failure. So, your error checking condition is incorrect.
Copying src to dest is quite unnecessary. Nor do you need to set the pointer to NULL after deletion.
Also, you have a race condition between remove(fileName) and CreateFile. You don't need to remove — setting dwCreationDisposition is sufficient.
The whole function could be written as:
void createImageFile(unsigned short* src, int srcLength, const char* fileName)
{
using namespace std;
ofstream stream(fileName, ios_base::binary | ios_base::trunc);
stream.write(src, srcLength * sizeof(unsigned short));
}
So basically I wish to write a byte array to a file, however the program crashes.
Unhandled exception at 0x7766DEE1 (KernelBase.dll) in append.exe: 0xC0000005: Access violation writing location 0x00000000.
BYTE *image ;
BYTE *bigMem;
#define REASONABLY_LARGE_BUFFER 16777216
file = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
fileSize = GetFileSize(file, NULL);
bigMem = (BYTE *)HeapCreate(NULL, REASONABLY_LARGE_BUFFER, 0);
image = (BYTE *)HeapAlloc(bigMem, HEAP_ZERO_MEMORY, fileSize);
if (bigMem == NULL || image == NULL){
printf("Allocation failed");
return EXIT_FAILURE;
}
printf("We are writing to the file %p, with data location %p, and filesize %d\n", file, image, fileSize);
LPDWORD at = 0;
WriteFile(file, image, fileSize, at, NULL);
That print says:
We are writing to the file 00000038, with data location 02451590, and filesize 161169
The argument passed to WriteFile used to store the number of bytes written (at) can only be null if the argument for the overlapped structure is not null. I suggest changing at to be a DWORD and pass a pointer to it.
DWORD at;
WriteFile(file, image, fileSize, &at, NULL);
Ok so I've been following this tutorial: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=4422&lngWId=3
And so far I've gotten everything to work, up until I need the program to load in a .raw audio file.
Here's the relevant code:
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD size = 0;
DWORD readBytes = 0;
void* block = NULL;
//open the file
if((hFile = CreateFile((LPCWSTR)filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// get it's size, allocate memory, and then read it into memory
size = GetFileSize(hFile, NULL);
block = HeapAlloc(GetProcessHeap(), 0, size);
ReadFile(hFile, block, size, &readBytes, NULL);
CloseHandle(hFile);
*blockSize = size;
return (LPSTR)block;
}
And then my main function which calls it:
int _tmain(int argc, _TCHAR* argv[])
{
HWAVEOUT hWaveOut; //device handle
WAVEFORMATEX wfx; //struct for format info
MMRESULT result; // for waveOut return values
LPSTR block;
DWORD blockSize;
// first let's set up the wfx format struct
wfx.nSamplesPerSec = 44100; // rate of the sample
wfx.wBitsPerSample = 16; //sample size
wfx.nChannels = 2; // 2 channels = stereo
wfx.cbSize = 0; // no extra info
wfx.wFormatTag = WAVE_FORMAT_PCM; //PCM format
wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
// then let's open the device
if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
{
fprintf(stderr, "unable to open Wave Mapper device.\n");
Sleep(1000);
ExitProcess(1);
}
// if no errors then close it
printf("The Wave Mapper device was opened successfully!\n");
//load and play file
if((block = loadAudioBlock("ding.raw", &blockSize)) == NULL)
{
fprintf(stderr, "Unable to load file\n");
Sleep(1000);
ExitProcess(1);
}
writeAudioBlock(hWaveOut, block, blockSize);
Sleep(1000);
waveOutClose(hWaveOut);
return 0;
}
Everytime I run the program I get the: "Unable to load file" output. I've got the "ding.raw" file in the same directory as my exe. I've also tried doing the full path as "C://path" and "C:/path" but then the compiler just gives me more errors about being unable to load a pdb file.
Any ideas? I'm using the Visual Studio 2012 Professional IDE and compiler.
Instead of using the standard char you should be using e.g. _TCHAR and LPCTSTR everywhere. This will make all string and string pointers you pass around be correct.
Look at the argv argument to _tmain and you will see that it uses _TCHAR instead of char. This is because Windows support both normal characters and Unicode characters depending on a couple of macros. See e.g. here for some more information.
So to solve what is likely your problem (since you don't get the actual error code, see my comment about GetLastError) you should change the function like this:
void *loadAudioBlock(LPCTSTR filename, DWORD* blockSize)
{
// ...
if((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// ...
}
And call it like this:
// ...
void *block;
if((block = loadAudioBlock(_T("C:\\path\\ding.raw"), &blockSize)) == NULL)
{
fprintf(stderr, "unable to open Wave Mapper device, error code %ld.\n", GetLastError());
Sleep(1000);
ExitProcess(1);
}
// ...
As you can see I also changed the return type, as the file is binary and won't have any readable text.
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
if((hFile = CreateFile(CA2T(filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
}
See ATL conversion macros: http://msdn.microsoft.com/en-us/library/87zae4a3%28v=vs.80%29.aspx Just casting const char* LPCWSTR doesn't work.
I'm trying to parse a text file with a win32 program in c++. Is there a simple method of reading a text file line by line? My text file consists of strings that I would like to store in a char array(const char* cArray[67]). Here is what I have so far. I am using CreateFile and ReadFile. I get an access violation error(0x000003e6) from readfile:
CDECK::CDECK():filename(".\\Deck/list.txt")
{
LPVOID data = NULL;
hFile = CreateFileA(filename, GENERIC_READ,FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
MessageBox(NULL, L"Failed to CreateFile - 'hFile'", L"CDECK::CDECK()", MB_OK);
DWORD fileSize = GetFileSize(hFile, &fileSize);
DWORD read = -1;
if(!ReadFile(hFile, data, fileSize, &read, NULL))
{
DWORD err = GetLastError();
MessageBox(NULL, L"Failed to ReadFile - 'hFile'", L"CDECK::CDECK()", MB_OK);
}
return;
}
Is there a simple method of reading a text file line by line?
Yes:
{
std::ifstream hFile(filename);
std::vector<std::string> lines;
std::string line;
while(std::getline(hFile, line))
lines.push_back(line);
return lines;
}
Consider this code:
LPVOID data = NULL;
if(!ReadFile(hFile, data, fileSize, &read, NULL))
Here data is null, and the following argument is the size of the entire file. You are supposed to allocate a buffer, and then pass a pointer to such buffer and its size to it. There is where the ReadFile function will write the readed bytes.
Here is a simple way of getting it to work with a statically sized buffer:
char data[4096] = {};
if(!ReadFile(hFile, static_cast< LPVOID >( &data ), 4096, &read, NULL))
Your problem is that you are reading the bytes of the file, to read the string you need to alloc a string location using SysAllocStringByteLen and then use the ReadFile
You forgot to allocate a buffer space before reading your data :
LPVOID data = NULL;
Before reading you must allocate a fileSize buffer space :
data = malloc(fileSize);
And probably must also declare your data variable as char* instead of void*