Serialization problem

N

Nikola Novak

Hello,

I'm trying to serialize an array of System.Drawing.Color objects and so far
I've had no luck.

Here are the relevant parts of my code:

public partial class fMain : Form
{
// ...
private Color[] ColorOrder = new Color[] { Color.Blue, Color.Red, Color.Pink, Color.Green, Color.Gray };
// ...

public fMain()
{
// ...
DeserializeColorOrder();
}

// ...

private void fMain_FormClosing(object sender, FormClosingEventArgs e)
{
// ...
SerializeColorOrder();
}

// ...

private void SerializeColorOrder()
{
FileStream swColorOrder = new FileStream("colororder.dat", FileMode.Create);
BinaryFormatter bfColorOrderSer = new BinaryFormatter();
try
{
bfColorOrderSer.Serialize(swColorOrder, ColorOrder);
}
catch (SerializationException)
{
MessageBox.Show("Error");
}
swColorOrder.Close();
}

private void DeserializeColorOrder()
{
FileStream srColorOrder = new FileStream("colororder.dat", FileMode.OpenOrCreate);
try
{
BinaryFormatter bfColorOrder = new BinaryFormatter();
ColorOrder = (Color[])bfColorOrder.Deserialize(srColorOrder);
}
catch (SystemException)
{
ColorOrder = new Color[] { Color.Blue, Color.Red, Color.Pink, Color.Green, Color.Gray };
}
finally
{
srColorOrder.Close();
}
}
}

What happens is that nothing is serialized. File "colororder.dat" is
created upon exiting the application, but it is empty. The FormClosing
event is executed as expected (tried it under debug), but nothing is
written in the file.

What am I doing wrong?

Thanks,
Nikola
 
I

Ignacio Machin ( .NET/ C# MVP )

What happens is that nothing is serialized. File "colororder.dat" is
created upon exiting the application, but it is empty. The FormClosing
event is executed as expected (tried it under debug), but nothing is
written in the file.

It work here (at least the serialization method) it correctly created
the file with a size of 315 bytes.
 
N

Nikola Novak

It work here (at least the serialization method) it correctly created
the file with a size of 315 bytes.

That is most unusual. I've copied the code exactly as I have it written in
my program, and mine doesn't serialize. Any ideas what might be wrong?
Maybe my .NET Framework is broken?

One more thing if I may, could you please try and run the code a couple of
more times (delete the old serialized file). Mine also worked once, but
then stopped working after I executed the code a few more times.

Thanks
Nikola
 
N

Nikola Novak

That is most unusual. I've copied the code exactly as I have it written in
my program, and mine doesn't serialize. Any ideas what might be wrong?
Maybe my .NET Framework is broken?

One more thing if I may, could you please try and run the code a couple of
more times (delete the old serialized file). Mine also worked once, but
then stopped working after I executed the code a few more times.

Thanks
Nikola

OK, forget about that, no need to try. I found some other odd thing. For
example, if I modify my Deserialization function to look like this:

private void DeserializeColorOrder()
{
FileStream srColorOrder = new FileStream("colororder.dat", FileMode.OpenOrCreate);
BinaryFormatter bfColorOrder = new BinaryFormatter();
try
{
ColorOrder = (Color[])bfColorOrder.Deserialize(srColorOrder);
}
catch (SystemException)
{
ColorOrder = new Color[] { Color.Blue, Color.Red, Color.Pink, Color.Green, Color.Gray };
bfColorOrder.Serialize(srColorOrder, ColorOrder);
}
finally
{
srColorOrder.Close();
}
}

Then ColorOrder gets serialized. However, the Serialization function still
doesn't work. The file colororder.dat should at least be emptied when I
open it with FileMode.Create option, but it isn't. Neither is anything
serialized. I've run the thing in debug mode and I'm certain that the
Serialization function is executed because execution stops at breakpoint.
But the program doesn't delete the file, doesn't serialize, and no
exception is thrown...
 
N

Nikola Novak

OMG disregard everything, I figured it out. I had an OpenFileDialog in my
code which I used to open a file (quite ingenious of me, heh), and when I
did that, it changed my working directory, so the file was saved there
instead of where I expected it to be.

Cheers,
Nikola
 
J

Jeff Johnson

OMG disregard everything, I figured it out. I had an OpenFileDialog in my
code which I used to open a file (quite ingenious of me, heh), and when I
did that, it changed my working directory, so the file was saved there
instead of where I expected it to be.

So tell us all the lesson you've learned:

"From now on I will ALWAYS ____ ____ ____."
 
P

puzzlecracker

OMG disregard everything, I figured it out. I had an OpenFileDialog in my
code which I used to open a file (quite ingenious of me, heh), and when I
did that, it changed my working directory, so the file was saved there
instead of where I expected it to be.

Cheers,
Nikola

Nikola, why don't you post a complete and working solution so that
others can learn from you or perhaps find more problems.

Thanks
 
N

Nikola Novak

Nikola, why don't you post a complete and working solution so that
others can learn from you or perhaps find more problems.

Thanks

Because it's over 1000 lines of code.
 
J

Jeff Johnson

Nikola, why don't you post a complete and working solution so that
others can learn from you or perhaps find more problems.

There's no real need to go that far. The problem was with this line:

FileStream srColorOrder = new FileStream("colororder.dat",
FileMode.OpenOrCreate);

No path info. Always specify a path.
 
N

Nikola Novak

HAHAHAHAHAHAHA!!

(Wouldn't change a thing in this case, though.)

Sure it would. In C++, classes I create don't suddenly modify properties of
classes they are seemingly unrelated to. Why SHOULD an OpenFileDialog
change the working directory? Just because it's in the manual? (well, even
if it is, I sure can't find that nugget of info in MSDN)
 
N

Nikola Novak

The solution wasn't 1000 lines of code. Even the wrong solution (saving
and restoring the directory around the call to ShowDialog()) is only a few
lines, and the correct solution is a one-liner:

ofd.RestoreDirectory = true;

(where "ofd" is a variable referencing the OpenFileDialog instance being
used, and where that line appears before the call to ShowDialog()).

Pete

You're not reading what puzzlecracker is asking: he wants the "complete and
working solution". What you've written is neither complete, nor working.
 
N

Nikola Novak

[...]
"From now on I will ALWAYS ____ ____ ____."

Work in C++?

HAHAHAHAHAHAHA!!

(Wouldn't change a thing in this case, though.)

Sure it would. In C++, classes I create don't suddenly modify properties
of
classes they are seemingly unrelated to. Why SHOULD an OpenFileDialog
change the working directory? Just because it's in the manual? (well,
even
if it is, I sure can't find that nugget of info in MSDN)

Changing the working directory is a behavior of the unmanaged open file
dialog, and is inherited by the managed OpenFileDialog.

That's why there's the OFN_NOCHANGEDIR flag for the unmanaged version, and
the RestoreDirectory property for the OpenFileDialog class in .NET.

Maybe if you'd written your own open file dialog in C++, this issue
wouldn't have come up. But if you were doing the sensible thing and using
the existing Win32 API support for the dialog, it'd have the same exact
problem you're seeing in .NET.

Pete

It's a good thing I usually work in Linux.
 
N

Nikola Novak

You are reading too much into the words "complete and working solution".
I seriously doubt "puzzlecracker" really wanted or expected you to post
your entire program, when the only interesting part is how to avoid the
issue with the working directory being changed.

He wrote ">>A<< complete and working solution", not "YOUR complete and
working solution".

It is common courtesy, when one has posted a question to a newsgroup, if
one finds the solution oneself, to go ahead and post a complete answer to
one's own question for the benefit of others who may come along later
looking for a similar solution.

Just as you should not post your entire program when asking a question,
there is no need to post your entire program when answering a question.
The best code sample is a concise-but-complete code sample that gets the
point across; next-best is a concise code sample that gets the point
across. Frequently the latter is just as good as the former, and in
neither case does anyone want to see all the other stuff in your program
that has nothing to do with the question or answer.

Pete

Forgive me for not following "common courtesy". I don't visit newsgroups
often enough to learn its courtesies. However, I did explain what went
wrong, so if anyone has similar trouble, they can look into it. Come up
with the solution all their own.

Nikola
 
N

Nikola Novak

Why? Is there something about Linux that allows a person to write code
without reading the documentation, or without understanding how the basic
OS API works?

In any case, the real lesson here is that you shouldn't be making
assumptions about the working directory when dealing with filenames. This
is true even in non-Windows operating systems, including Linux. File i/o
operations should specify a complete path, because there's no way for the
code trying the operation to guarantee that the default/working directory
is correct for that code (unless it sets it explicitly, but that's only
safe in a single-threaded environment anyway).

Pete

There is nothing about Linux that allows a person to write code without
reading the documentation, of course. However, there is one thing about
Linux that makes it much easier for a programmer to know what's going on in
a given scenario, and that's the fact that the documentation is complete
and unambiguous (or at least the part of it that I read was).

I've often found a solution to my problem on Linux on its 'man' pages.
Here, the particular property I should have been looking at for this to not
happen (RestoreDirectory) is explained ambiguously enough for me to think
it does something completely different -- something I don't want for it to
do, so I've had it deliberately set to false, which is its default value.

Never does MSDN say that OFD, or any other control/dialog will change my
working directory, so I was content with having the following line written
in my constructor:

Directory.SetCurrentDirectory(Path.GetDirectoryName(Application.ExecutablePath));

An equivalent code in C++ on Linux would've been enough to ensure that all
fopen's (or whatever other functions I use for opening files) in my code
open my files in the same directory as the executable that started it is
placed in -- unless I specify otherwise.

Nikola
 
N

Nikola Novak

I've never seen any documentation that was 100% "complete and
unambiguous". Not even in Linux. If that's the only kind of Linux docs
you've seen, you've been lucky so far.

But in any case, you are using OpenFileDialog as a red herring here. Yes,
it offers a way to avoid the problem (and IMHO it's well-enough documented
to discover, even if it's not as obvious as it could be). But the real
issue here is that your code relies on the working directory, which it
shouldn't.

The code that's actually broken was the code trying to open a different
file, not the code showing the OpenFileDialog. And that code would be
broken on Linux too.

Pete

Why? What could happen that could change my working directory in Linux so
unexpectedly, while the application is running?
 
N

Nikola Novak

Of course it would be. It's a code maintenance issue. When you make one
section of the code susceptible to side-effects of other code, then you
have to remember forever that vulnerability exists, otherwise the
possibility of breaking the original code is a very real one.

If you think you are capable of remembering something that long, you're
mistaken. Which means that the possibility of breaking the original code
is _always_ a very real possibility.

Pete

I see. Thanks for clearing this up.

Nikola
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top