Link to home
Start Free TrialLog in
Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on

CFile and UNICODE

Ah hello.

I am writing out a CMyClass object (very simple class, contains a couple of integers and a BOOL) using CFile

      CFile f;
      if( !f.Open( _T("C:\\Test.txt"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary ) ) ASSERT(FALSE);
      CMyClass myClass(1, 2, TRUE);
      f.Write((void*)&myClass, sizeof(myClass));

      f.Close();

      if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
      CMyClass* pmyClass = new CMyClass();
      f.Read((void*)pmyClass, sizeof(CMyClass));

and all this works fine.

My concern is now that I am thinking about adding a CString member to the class, I dont want to break anything if the CString contains foreign characters.  

In short, is what I am currently doing going to be UNICODE safe ?

TIA
Avatar of rajeev_devin
rajeev_devin

>> I am thinking about adding a CString member to the class
If you add CString then it won't work the same way.
Avatar of AndyAinscow
What you are doing is storing the contents of the object.
>> CMyClass myClass(1, 2, TRUE);
>> f.Write((void*)&myClass, sizeof(myClass));

If you add CString
class CMyClass
{
   int x;
   CString str;
}

CMyClass::CMyClass()
{
   x = 10;        // 4 bytes
   str = "Hello world" // 11 bytes
}

You are expection the sizeof the object to be 15 (4+11).
But it is not, because CString just contains one pointer.

In that case you will just copy the pointer value.
Avatar of mrwad99

ASKER

>> If you add CString then it won't work the same way.

Hmm.  That is useful.  Care to elaborate on why ?

Andy:  thanks.  I think I saw that link before, and it made me decide to use serialisation instead.  Maybe that too is the answer here...
Avatar of mrwad99

ASKER

Thanks for that rajeev_devin.

Interestingly, I did try this, and I did notice that no matter how long the CString, the size was consistent.  The code did not crash however, and the read CString was the same as the stored CString.

Why could that have been ?
Avatar of mrwad99

ASKER

Overall, is there any way I can use CFile::Write and still output a string ?  Could I use a TCHAR[] or something ?

Or is serialisaion the only answer ?

TIA
Are you writing and reading in the same object ???
>> Overall, is there any way I can use CFile::Write and still output a string ?  Could I use a TCHAR[] or something ?
That is better.
You can use TCHAR array. But remember not pointer.
Something like this
class CMyClass
{
   int x;
   TCHAR[1000];
}
In CMyClass have two functions Read, Write each of which takes a CFile pointer.
That way the class takes care of itself - change the class, change the code inside the class.


Back to UNICODE.
I am not certain if the CFile class is *really* suitable with UNICODE - some things I read say it isn't, hence the link I posted.  It may allow you to write safe code inside the CMyClass where it reads/writes the UNICODE strings to the text file.
Avatar of mrwad99

ASKER

rajeev_devin

This is my code:

class CMyClass : public CObject
{
 public:
      CMyClass() {}
      CMyClass(int i, int j, BOOL b, CString str)
      {
            m_n1 = i;
            m_n2 = j;
            m_bBOOL = b;
            m_strString = str;
      }
      virtual ~CMyClass(void) {};
      
      int m_n1, m_n2;
      BOOL m_bBOOL;
      CString m_strString;
};

//...

      if( !f.Open( _T("C:\\Test.txt"), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary )) ASSERT(FALSE);
      CMyClass myClass( 10, 20, TRUE, _T("This is my string") );
      f.Write((void*)&myClass, sizeof(myClass));
      size_t size = sizeof(myClass);
      f.Close();

      if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
      CMyClass* pmyClass = new CMyClass();
      f.Read((void*)pmyClass, sizeof(CMyClass));

And this works fine!  'pmyClass' has the same values as 'myClass' !

?!
SOLUTION
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
This is correct the value will be same. Why?
Because in both case CString in pointing to the same address.
Avatar of mrwad99

ASKER

Yes, that is an excellent point.  Also, what if I add new members ?  That screws it up totally.

I think serialisation with versioning is the way to go.

I will close this once feedback is received as to why the code I posted works, when in theory it should not.

Thanks.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

>> Because in both case CString in pointing to the same address

Sorry, I dont get that.  What CString are you talking about ?  I construct two objects, so each has a different address.

?
>> Yes, that is an excellent point.
It is like that.
If you want to see the difference then in your program just read the value of that file.
You will see that the CString is garbage.

Do this

CFile f;
if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
CMyClass* pmyClass = new CMyClass();
f.Read((void*)pmyClass, sizeof(CMyClass));
mrwad99 - you might have missed my last comment.
>> Sorry, I dont get that.  What CString are you talking about ?
Simple example. I am excluding the ctor and dtor.

class CMyClass {
   m_strString; // It is pointing to the string in location say 1000.
};

CMyClass myClass("This is a test");
write(&myClass, ...);

CMyClass* pmyClass = new CMyClass();
Read(pmyClass, sizeof(CMyClass));

value of

pmyClass
{
   // 1000 which is the same string.
}
Avatar of mrwad99

ASKER

Ha !

I absolutely see the problem.  Adding an explicit call to

      myClass.~CMyClass();

before reading back from the file shows that pmyFile has an m_strString member that is full of rubbish.

Overall, I am going to use serialisation, mainly as a result of what Andy said about adding/changing variables etc.

Thanks both, I will close this now :)
>> I construct two objects, so each has a different address.
As I said before CString class only contains a pointer. Something like this

CString {
   char* data; // Here is the pointer.
}

Therefore its size will be 4. Always
I don't know whether the thing is clear to you ?
Avatar of mrwad99

ASKER

I have posted a follow on to this at http:Q_21795040.html

Any participation welcome :)
Avatar of mrwad99

ASKER

rajeev_devin: yes, your explanation was excellent.  I understand why I cannot use CString in the manner I was doing.  Thank you.