Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 2026
  • Last Modified:

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
0
mrwad99
Asked:
mrwad99
  • 11
  • 9
  • 4
2 Solutions
 
rajeev_devinCommented:
>> I am thinking about adding a CString member to the class
If you add CString then it won't work the same way.
0
 
AndyAinscowCommented:
0
 
rajeev_devinCommented:
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.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
mrwad99Author Commented:
>> 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...
0
 
mrwad99Author Commented:
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 ?
0
 
mrwad99Author Commented:
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
0
 
rajeev_devinCommented:
Are you writing and reading in the same object ???
0
 
rajeev_devinCommented:
>> 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.
0
 
rajeev_devinCommented:
You can use TCHAR array. But remember not pointer.
Something like this
class CMyClass
{
   int x;
   TCHAR[1000];
}
0
 
AndyAinscowCommented:
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.
0
 
mrwad99Author Commented:
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' !

?!
0
 
AndyAinscowCommented:
Look at test.txt with notepad - see what has been written.

Now do something really dim and change the order of the variables and read the file (don't overwrite it first).  IMHO it is safer (and better coded?) to encapsulate the read/write inside the CMyClass itself.  Changes you then make to CMyClass are hidden from the rest of the app, you don't need to search all over the place for code snippets to update.
0
 
rajeev_devinCommented:
This is correct the value will be same. Why?
Because in both case CString in pointing to the same address.
0
 
mrwad99Author Commented:
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.
0
 
rajeev_devinCommented:
>> CMyClass myClass( 10, 20, TRUE, _T("This is my string") );
>> f.Write((void*)&myClass, sizeof(myClass));
>> f.Close();
CString of myClass is pointing to a location that you are storing using Write.

>> if( !f.Open( _T("C:\\Test.txt"), CFile::modeRead | CFile::typeBinary ) ) ASSERT(FALSE);
>> CMyClass* pmyClass = new CMyClass();
>> f.Read((void*)pmyClass, sizeof(CMyClass));
Now the CString of pmyClass has the same address as myClass.
Therefore, it is pointing to the same data.

I hope its clear.
0
 
mrwad99Author Commented:
>> 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.

?
0
 
rajeev_devinCommented:
>> 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));
0
 
AndyAinscowCommented:
mrwad99 - you might have missed my last comment.
0
 
rajeev_devinCommented:
>> 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.
}
0
 
mrwad99Author Commented:
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 :)
0
 
rajeev_devinCommented:
>> 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
0
 
rajeev_devinCommented:
I don't know whether the thing is clear to you ?
0
 
mrwad99Author Commented:
I have posted a follow on to this at http:Q_21795040.html

Any participation welcome :)
0
 
mrwad99Author Commented:
rajeev_devin: yes, your explanation was excellent.  I understand why I cannot use CString in the manner I was doing.  Thank you.
0

Featured Post

[Webinar] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

  • 11
  • 9
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now