Jump to content
  • Advertisement
Sign in to follow this  
MatsVed

Loading files in C++... (crashing)

This topic is 3073 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'm trying to load a saved file in C++. The problem is that I'm calling the DLL from UnrealScript, and don't really have a good way to debugging it. I can only confirm that it makes UDK crash. So... can anyone spot any obvious flaws in my loading code (compiles fine)?
// SaveLib.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include "OSFDlg.h"

using namespace std;

extern "C"
{
	__declspec(dllexport) unsigned int SaveGame(wchar_t* LevelName, float X, float Y, float Z, wchar_t* SavePath)
	{
		wofstream SaveStream(SavePath, ios::out);
		SaveStream << LevelName;
		SaveStream << X;
		SaveStream << Y;
		SaveStream << Z;
		SaveStream.close();

		return 1;
	}

	struct Save
	{
		wchar_t LevelName;
		float X, Y, Z;
	};

	__declspec(dllexport) Save* LoadGame(wchar_t* LoadPath)
	{
		wifstream LoadStream(LoadPath, ios::in);

		static Save *NewSave;
		NewSave = new Save;

		LoadStream >> NewSave->LevelName;
		LoadStream >> NewSave->X;
		LoadStream >> NewSave->Y;
		LoadStream >> NewSave->Z;
		LoadStream.close();

		return NewSave;
	}

	__declspec(dllexport) wchar_t SaveDiag()
	{
		//Filter
		TCHAR szFilter[] = TEXT("Save Files (*.SAV)\0*.sav\0");
		//Default extension
		TCHAR szDefExtension[] = TEXT("sav\0");

		COSFDialog SaveDiag;

		if(SaveDiag.FileSaveDlg(szFilter, szDefExtension, NULL))
		{
			return (wchar_t)SaveDiag.GetFileName();
		}
	}

	__declspec(dllexport) wchar_t LoadDiag()
	{
		//Filter
		TCHAR szFilter[] = TEXT("Save Files (*.SAV)\0*.sav\0");
		//Default Extension
		TCHAR szDefExtension[] = TEXT("sav\0");

		COSFDialog LoadDiag;

		if(LoadDiag.FileOpenDlg(szFilter, szDefExtension, TEXT("Load Game"), false))
			return (wchar_t)LoadDiag.GetFileName();
	}
}

Edit: It's the LoadGame() function that fails. LoadDiag seems to work fine... it just displays a File Open Dialog.

Share this post


Link to post
Share on other sites
Advertisement
In terms of debugging you can attach to an already running process in Visual Studio. All you really need to do is:

-Make the program wait somewhere to give you a chance to attach, something like

static bool wait = true;
while(wait) {}

at the top of the crashing function should do it.

-Perform the steps to recreate the crash, you should find that the program then hangs at the while loops instead of crashing.

-In Visual Studio goto "Debug"->"Attach To Process" and choose your dll or UDK editor process (this can be a bit of trail and error :S ).

You can then change the wait to false and step through the code :)

This feature probably exists with other IDE's if you're not using Visual Studio.

Share this post


Link to post
Share on other sites
I don't have access to the Unreal sourcecode. :(
But I'm gonna do some MessageBox debugging to check the sanity of my variables etc

Share this post


Link to post
Share on other sites
Quote:
Original post by MatsVed
I don't have access to the Unreal sourcecode. :(
But I'm gonna do some MessageBox debugging to check the sanity of my variables etc


Why would you need it? you can still debug your DLL (as I understand it you are writing a DLL that unreal loads )

Share this post


Link to post
Share on other sites
You don't need to actually debug this using UDK, just create a basic project that contains your loading/saving code...


#include <iostream>
#include <fstream>

struct Save
{
wchar_t LevelName;
float X, Y, Z;
};

template <typename Stream>
Stream& operator << (Stream& stream, const Save& save)
{
stream << save.LevelName;
stream << save.X;
stream << save.Y;
stream << save.Z;
return stream;
}

template <typename Stream>
Stream& operator >> (Stream& stream, Save& save)
{
stream >> save.LevelName;
stream >> save.X;
stream >> save.Y;
stream >> save.Z;
return stream;
}

int main(int argc, char* argv[])
{
{
Save test;

test.X = 2.0f;
test.Y = 4.0f;
test.Z = 8.0f;
test.LevelName = L'T';

std::wofstream os("test.txt");
os << test;
}
{
Save test;
std::wifstream is("test.txt");
is >> test;
}

return 0;
}



If you take a look at the contents of test.txt that should give you some clue as to why this is not working:


T248


How should operator >> intepret this data into a wide char and three floats? You need some way to distinguish which part of the text belongs to which field, for example you could put each field on a seperate line, or use some other token to delimit the fields:


T
2
4
8




template <typename Stream>
Stream& operator << (Stream& stream, const Save& save)
{
stream << save.LevelName << '\n';
stream << save.X << '\n';
stream << save.Y << '\n';
stream << save.Z << '\n';
return stream;
}

template <typename Stream>
Stream& operator >> (Stream& stream, Save& save)
{
std::wstring str;

std::getline(stream, str);
save.LevelName = boost::lexical_cast<wchar_t>(str);

std::getline(stream, str);
save.X = boost::lexical_cast<float>(str);

std::getline(stream, str);
save.Y = boost::lexical_cast<float>(str);

std::getline(stream, str);
save.Z = boost::lexical_cast<float>(str);

return stream;
}



Although if you are willing to use boost there is a great serialisation library included which will handle this for you easily, as well as providing different archive types.

Share this post


Link to post
Share on other sites
I actually did this earlier:

	__declspec(dllexport) unsigned int SaveGame(wchar_t* LevelName, float X, float Y, float Z, wchar_t* SavePath)
{
wofstream SaveStream(SavePath, ios::out);
SaveStream << LevelName;
SaveStream << std::endl;
SaveStream << X;
SaveStream << std::endl;
SaveStream << Y;
SaveStream << std::endl;
SaveStream << Z;
SaveStream << std::endl;
SaveStream.close();

return 1;
}


But it didn't seem to have any effect, so I removed it. Is there any standard equivalent to boost:lexical_cast?

Share this post


Link to post
Share on other sites
Quote:
Original post by MatsVed
I actually did this earlier:

*** Source Snippet Removed ***

But it didn't seem to have any effect, so I removed it.


It may well be that the crash is caused by something else, but your load/save code is definately broken without some delimeter between the fields. I imagine that one or more of those variables will remain uninitialised. Do you have any more information about the crash?

Quote:

Is there any standard equivalent to boost:lexical_cast?


I believe it is part of tr2 although you can simulate the effect quite simply (I'm pretty sure the boost::lexical_cast does some other trickery, including error conditions and such):


template <typename Target, typename Source>
Target lexical_cast(Source source)
{
Target target;

std::ostringstream os;
os << source;
std::istringstream is(os.str());
is >> target;

return target;
}

Share this post


Link to post
Share on other sites
Ok, so I got the thing to work in UDK (turns out I was doing something wrong with the UnrealScript code).
But I still have a problem... no text is actually read from the file and into the struct I'm returning. :
I created a test program for myself, and a ReadLine function.

// LoadTest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include "OSFDlg.h"
#include <assert.h>

using namespace std;

template <typename Target, typename Source>
Target lexical_cast(Source source)
{
Target target;

std::ostringstream os;
os << source;
std::istringstream is(os.str());
is >> target;

return target;
}

struct Save
{
wchar_t *LevelName;
float X, Y, Z;
};

wchar_t LoadDiag()
{
//Filter
TCHAR szFilter[] = TEXT("Save Files (*.SAV)\0*.sav\0");
//Default Extension
TCHAR szDefExtension[] = TEXT("sav\0");

COSFDialog LoadDiag;

if(LoadDiag.FileOpenDlg(szFilter, szDefExtension, TEXT("Load Game"), false))
return (wchar_t)LoadDiag.GetFileName();
}

wchar_t* ReadLine(wifstream *Stream)
{
wchar_t *Line = new wchar_t[256];
wchar_t ControlChar = '0';
int i = 0;

while(ControlChar != '\n')
{
ControlChar = Stream->get();
Line = ControlChar;

i++;

if(i == 256)
break;
}

return Line;
}

__declspec(dllexport) Save* LoadGame(wchar_t* LoadPath)
{
wifstream LoadStream(LoadPath, ios::in);
wchar_t X;
wchar_t Y;
wchar_t Z;

static Save NewSave;

NewSave.LevelName = new wchar_t[100];

NewSave.LevelName = ReadLine(&LoadStream);
LoadStream >> X;
NewSave.X = lexical_cast<float, wchar_t>(X);
LoadStream >> Y;
NewSave.Y = lexical_cast<float, wchar_t>(Y);
LoadStream >> Z;
NewSave.Z = lexical_cast<float, wchar_t>(Z);
/*LoadStream >> NewSave.X;
LoadStream >> NewSave.Y;
LoadStream >> NewSave.Z;*/


LoadStream.close();

MessageBox(NULL, (LPCWSTR)*NewSave.LevelName, TEXT("LoadGame()"), MB_OKCANCEL);

return &NewSave;
}

int _tmain(int argc, _TCHAR* argv[])
{
wchar_t SavePath = LoadDiag();
Save *Sav = LoadGame(&SavePath);

assert(Sav);

return 0;
}




When the MessageBox is displayed, it is empty! This makes me assume that no text is being read. So what is the problem here?

Share this post


Link to post
Share on other sites
I see, you are doing something wrong with that wchar_t in your MessageBox:

This:

MessageBox(NULL, (LPCWSTR)*NewSave.LevelName, TEXT("LoadGame()"), MB_OKCANCEL);


should become this:


MessageBox(NULL, (LPCWSTR)NewSave.LevelName, TEXT("LoadGame()"), MB_OKCANCEL);


NewSave.LevelName is a *wchar_t type. And the message box takes a
LPCWSTR
which is not more than an
const wchar_t*
.

Also, you don't delete the memory you allocate after use, or do you?


Anyways, this would be better:


struct Save
{
wchar_t LevelName[100];
float X, Y, Z;
};



So you don't need to allocate new memory. But note that you have to cast that string to a LPWSTR or an LPCWSTR when you want to use it!

(LPWSTR)&LevelName should do that.


Share this post


Link to post
Share on other sites
Hm.
I changed it to:

MessageBox(NULL, (LPCWSTR)NewSave.LevelName, TEXT("LoadGame()"), MB_OKCANCEL);


The messagebox is still empty. I'm worried that no data is getting read. How do I fix this? :\

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!