Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Problem Reading/Writing text/dat files

Problem Reading/Writing text/dat files

Scheduled Pinned Locked Moved C / C++ / MFC
helpdatabasetutorial
16 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Trupti Mehta

    Hello, I have serialized objects which I write in dat/txt files. While writing it doesn't throw any errors but I feel it writes only 1 record instead of 2 & while reading after reading 2, it doesn't stop. I might be missing something in reading case, as I don't know how to know the number of records in the file or how to trap when it should stop. The code for storing the objects in a Map & calling a function to write objects to/from map file.

    void COperatorDlg::OnBnClickedWriteBtn()
    {
    // TODO: Add your control notification handler code here
    CMap<int, int, OperatorDetails, OperatorDetails> newOperMap;

    DbOperations db;
    newOperMap.SetAt(1, OperatorDetails(1, _T("One")));
    newOperMap.SetAt(2, OperatorDetails(2, _T("Two")));
    db.WriteOperators(newOperMap);
    }

    void COperatorDlg::OnBnClickedReadBtn()
    {
    // TODO: Add your control notification handler code here
    CMap<int, int, OperatorDetails, OperatorDetails>* existOperMap;

    DbOperations db;
    existOperMap = db.ReadOperators();
    CString s = _T("Read Operators : ");
    s.Format(_T("%s %d"), s, existOperMap->GetCount());
    AfxMessageBox(s);
    }

    DbOperations::DbOperations()
    {
    operMap = new CMap<int, int, OperatorDetails, OperatorDetails>(10);
    deptMap = new CMap<int, int, DeptDetails, DeptDetails>(10);
    }

    // Write Operators to the file
    void DbOperations::WriteOperators(CMap<int, int, OperatorDetails, OperatorDetails> &opdtMap) {
    HANDLE hFile = CreateFile(OPER_FILE,
    GENERIC_WRITE, FILE_SHARE_WRITE,
    NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

    if (hFile == INVALID_HANDLE_VALUE)
    AfxMessageBox(_T("Error OPeniong File"));
    else {
    CFile myfile(hFile);
    int key;
    OperatorDetails od;

    CArchive ar(&myfile, CArchive::store);

    for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL;) {
    opdtMap.GetNextAssoc(pos, key, od );
    ar.WriteObject(&od);
    od.~OperatorDetails();
    }

    od.~OperatorDetails();
    ar.Close();
    myfile.Close();
    }

    return;
    }

    // Read Operators from the file
    CMap<int, int, OperatorDetails, OperatorDetails>* DbOperations::ReadOperators()
    {
    int count =0;
    if(operMap->IsEmpty() == false)
    operMap->RemoveAll();

    HANDLE hFile = CreateFile(OPER_FILE,
    GENERIC_READ, FILE_SHA

    M Offline
    M Offline
    Mark Salsbery
    wrote on last edited by
    #2

    Trupti Mehta wrote:

    The Error basically says an attempt to read after the end of the file & then unhandled exception.

    This isn't the correct way to loop through the archive:

    while (true) {
    od = (OperatorDetails*) ar.ReadObject( RUNTIME_CLASS(OperatorDetails) ); //************* I got to trap to stop
    if (od == NULL)
    break;

    ReadObject() throws exceptions instead of returning a NULL pointer. You can either write a count value to the archive and retrieve it when deserializing, or catch exceptions to break the loop. I personally prefer the first method FWIW. Mark

    Mark Salsbery Microsoft MVP - Visual C++ :java:

    T 1 Reply Last reply
    0
    • M Mark Salsbery

      Trupti Mehta wrote:

      The Error basically says an attempt to read after the end of the file & then unhandled exception.

      This isn't the correct way to loop through the archive:

      while (true) {
      od = (OperatorDetails*) ar.ReadObject( RUNTIME_CLASS(OperatorDetails) ); //************* I got to trap to stop
      if (od == NULL)
      break;

      ReadObject() throws exceptions instead of returning a NULL pointer. You can either write a count value to the archive and retrieve it when deserializing, or catch exceptions to break the loop. I personally prefer the first method FWIW. Mark

      Mark Salsbery Microsoft MVP - Visual C++ :java:

      T Offline
      T Offline
      Trupti Mehta
      wrote on last edited by
      #3

      Mark Salsbery wrote:

      ReadObject() throws exceptions instead of returning a NULL pointer

      In MSDN also I didn't found which exceptions ReadObject throws. http://msdn.microsoft.com/en-us/library/bkcy8aad(VS.80).aspx[^]

      Mark Salsbery wrote:

      either write a count value to the archive and retrieve it when deserializing,

      Can you guide me how to achieve the above, it would be really nice of you, Mark. Please. While writing to file, I should count the number of objects and store somewhere and before reading from file, first read that number & set the while loop accordingly. Or something else. Please guide me the best and appropriate way to achieve the goal.

      Thanks Terry

      M 1 Reply Last reply
      0
      • T Trupti Mehta

        Mark Salsbery wrote:

        ReadObject() throws exceptions instead of returning a NULL pointer

        In MSDN also I didn't found which exceptions ReadObject throws. http://msdn.microsoft.com/en-us/library/bkcy8aad(VS.80).aspx[^]

        Mark Salsbery wrote:

        either write a count value to the archive and retrieve it when deserializing,

        Can you guide me how to achieve the above, it would be really nice of you, Mark. Please. While writing to file, I should count the number of objects and store somewhere and before reading from file, first read that number & set the while loop accordingly. Or something else. Please guide me the best and appropriate way to achieve the goal.

        Thanks Terry

        M Offline
        M Offline
        Mark Salsbery
        wrote on last edited by
        #4

        Trupti Mehta wrote:

        I didn't found which exceptions ReadObject throws.

        Using the debug MFC library you may get an assertion. Exceptions you may want to catch - CMemoryException, CArchiveException, CException.

        Trupti Mehta wrote:

        Can you guide me how to achieve the above

        // Writing...

        CArchive ar(&myfile, CArchive::store);

        ar << (int)opdtMap.GetCount();

        for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL; )
        {
        opdtMap.GetNextAssoc(pos, key, od );
        ar << &od;
        }

        // Reading...

        CArchive ar(&myfile, CArchive::load);

        int count;
        ar >> count;

        for (int i = 0; i < count; i++)
        {
        ar >> od;
        ...

        Or you can just serialize the CMap, since CMaps are serializable :) Mark

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        T 1 Reply Last reply
        0
        • T Trupti Mehta

          Hello, I have serialized objects which I write in dat/txt files. While writing it doesn't throw any errors but I feel it writes only 1 record instead of 2 & while reading after reading 2, it doesn't stop. I might be missing something in reading case, as I don't know how to know the number of records in the file or how to trap when it should stop. The code for storing the objects in a Map & calling a function to write objects to/from map file.

          void COperatorDlg::OnBnClickedWriteBtn()
          {
          // TODO: Add your control notification handler code here
          CMap<int, int, OperatorDetails, OperatorDetails> newOperMap;

          DbOperations db;
          newOperMap.SetAt(1, OperatorDetails(1, _T("One")));
          newOperMap.SetAt(2, OperatorDetails(2, _T("Two")));
          db.WriteOperators(newOperMap);
          }

          void COperatorDlg::OnBnClickedReadBtn()
          {
          // TODO: Add your control notification handler code here
          CMap<int, int, OperatorDetails, OperatorDetails>* existOperMap;

          DbOperations db;
          existOperMap = db.ReadOperators();
          CString s = _T("Read Operators : ");
          s.Format(_T("%s %d"), s, existOperMap->GetCount());
          AfxMessageBox(s);
          }

          DbOperations::DbOperations()
          {
          operMap = new CMap<int, int, OperatorDetails, OperatorDetails>(10);
          deptMap = new CMap<int, int, DeptDetails, DeptDetails>(10);
          }

          // Write Operators to the file
          void DbOperations::WriteOperators(CMap<int, int, OperatorDetails, OperatorDetails> &opdtMap) {
          HANDLE hFile = CreateFile(OPER_FILE,
          GENERIC_WRITE, FILE_SHARE_WRITE,
          NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

          if (hFile == INVALID_HANDLE_VALUE)
          AfxMessageBox(_T("Error OPeniong File"));
          else {
          CFile myfile(hFile);
          int key;
          OperatorDetails od;

          CArchive ar(&myfile, CArchive::store);

          for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL;) {
          opdtMap.GetNextAssoc(pos, key, od );
          ar.WriteObject(&od);
          od.~OperatorDetails();
          }

          od.~OperatorDetails();
          ar.Close();
          myfile.Close();
          }

          return;
          }

          // Read Operators from the file
          CMap<int, int, OperatorDetails, OperatorDetails>* DbOperations::ReadOperators()
          {
          int count =0;
          if(operMap->IsEmpty() == false)
          operMap->RemoveAll();

          HANDLE hFile = CreateFile(OPER_FILE,
          GENERIC_READ, FILE_SHA

          T Offline
          T Offline
          ThatsAlok
          wrote on last edited by
          #5

          just a basic question, why don't use simple CStdioFile or CFile classes when you are building MFC app instead of raw api CreateFile. though i am big fan window api! just a thought !

          T 1 Reply Last reply
          0
          • M Mark Salsbery

            Trupti Mehta wrote:

            I didn't found which exceptions ReadObject throws.

            Using the debug MFC library you may get an assertion. Exceptions you may want to catch - CMemoryException, CArchiveException, CException.

            Trupti Mehta wrote:

            Can you guide me how to achieve the above

            // Writing...

            CArchive ar(&myfile, CArchive::store);

            ar << (int)opdtMap.GetCount();

            for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL; )
            {
            opdtMap.GetNextAssoc(pos, key, od );
            ar << &od;
            }

            // Reading...

            CArchive ar(&myfile, CArchive::load);

            int count;
            ar >> count;

            for (int i = 0; i < count; i++)
            {
            ar >> od;
            ...

            Or you can just serialize the CMap, since CMaps are serializable :) Mark

            Mark Salsbery Microsoft MVP - Visual C++ :java:

            T Offline
            T Offline
            Trupti Mehta
            wrote on last edited by
            #6

            Oh Thaks Mark, this helped me get rid of the Assertion Errors/Exceptions. But still my condition hasn't improved, its in almost same place. I store 2 objs in a map & send it to write.

            newOperMap.SetAt(1, OperatorDetails(1, \_T("One")));
            newOperMap.SetAt(2, OperatorDetails(2, \_T("Two")));
            db.WriteOperators(newOperMap);
            

            Write method

            	for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL;) {
            		int key;
            		OperatorDetails od;
            		opdtMap.GetNextAssoc(pos, key, od ); 
            

            // ar.WriteObject(&od);
            ar << &od;
            }

            Executes for loop 2 times, od has respectives values i.e. "Two" followed by "One". In my text file, I can see only "Two":

             ÿÿ
             OperatorDetails Two

            While Reading:

            		OperatorDetails\* od;
            	
            	for (int i=0; i < count; i++) {
            		OperatorDetails odObj;
            		ar >> od;
            		if (od == NULL)
            			break;
            		
            		odObj.SetOperatorNo(od->GetOperatorNo());
            		odObj.SetOperName(od->GetOperName());
            		operMap->SetAt(odObj.GetOperatorNo(), odObj);
            	}
            		delete od;
            

            For loop executes twice as count is stored as 2 records while writing. Both the times it gets only "Two". So number of records actually retrieved are only 1 as the key is the same 2. While writing though &od has the proper object 2nd time i.e. 1 One, still it doesn't write only. ar << &od is also executing properly, still somehow something is acting weird. Can you help me figure out that improper stuff. Would be glad enough & able to take a relaxed breath.

            Thanks Terry

            M 2 Replies Last reply
            0
            • T ThatsAlok

              just a basic question, why don't use simple CStdioFile or CFile classes when you are building MFC app instead of raw api CreateFile. though i am big fan window api! just a thought !

              T Offline
              T Offline
              Trupti Mehta
              wrote on last edited by
              #7

              Alok, this application is especially meant for development in eVC++ with WinCe. CStudioFile is not supported. So got to opt raw api of C/C++.

              Thanks Terry

              T 1 Reply Last reply
              0
              • T Trupti Mehta

                Alok, this application is especially meant for development in eVC++ with WinCe. CStudioFile is not supported. So got to opt raw api of C/C++.

                Thanks Terry

                T Offline
                T Offline
                ThatsAlok
                wrote on last edited by
                #8

                just a question are ATL header files are available for eVC, you could use CAtlFile Class [^]

                T 1 Reply Last reply
                0
                • T Trupti Mehta

                  Oh Thaks Mark, this helped me get rid of the Assertion Errors/Exceptions. But still my condition hasn't improved, its in almost same place. I store 2 objs in a map & send it to write.

                  newOperMap.SetAt(1, OperatorDetails(1, \_T("One")));
                  newOperMap.SetAt(2, OperatorDetails(2, \_T("Two")));
                  db.WriteOperators(newOperMap);
                  

                  Write method

                  	for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL;) {
                  		int key;
                  		OperatorDetails od;
                  		opdtMap.GetNextAssoc(pos, key, od ); 
                  

                  // ar.WriteObject(&od);
                  ar << &od;
                  }

                  Executes for loop 2 times, od has respectives values i.e. "Two" followed by "One". In my text file, I can see only "Two":

                   ÿÿ
                   OperatorDetails Two

                  While Reading:

                  		OperatorDetails\* od;
                  	
                  	for (int i=0; i < count; i++) {
                  		OperatorDetails odObj;
                  		ar >> od;
                  		if (od == NULL)
                  			break;
                  		
                  		odObj.SetOperatorNo(od->GetOperatorNo());
                  		odObj.SetOperName(od->GetOperName());
                  		operMap->SetAt(odObj.GetOperatorNo(), odObj);
                  	}
                  		delete od;
                  

                  For loop executes twice as count is stored as 2 records while writing. Both the times it gets only "Two". So number of records actually retrieved are only 1 as the key is the same 2. While writing though &od has the proper object 2nd time i.e. 1 One, still it doesn't write only. ar << &od is also executing properly, still somehow something is acting weird. Can you help me figure out that improper stuff. Would be glad enough & able to take a relaxed breath.

                  Thanks Terry

                  M Offline
                  M Offline
                  Mark Salsbery
                  wrote on last edited by
                  #9

                  First, I would change the CMap ARG_KEY and ARG_VALUE types to references:

                  CMap<int, int&, OperatorDetails, OperatorDetails&>

                  Second, can you post the OperatorDetails::Serialize() code? Mark

                  Mark Salsbery Microsoft MVP - Visual C++ :java:

                  T 1 Reply Last reply
                  0
                  • T Trupti Mehta

                    Oh Thaks Mark, this helped me get rid of the Assertion Errors/Exceptions. But still my condition hasn't improved, its in almost same place. I store 2 objs in a map & send it to write.

                    newOperMap.SetAt(1, OperatorDetails(1, \_T("One")));
                    newOperMap.SetAt(2, OperatorDetails(2, \_T("Two")));
                    db.WriteOperators(newOperMap);
                    

                    Write method

                    	for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL;) {
                    		int key;
                    		OperatorDetails od;
                    		opdtMap.GetNextAssoc(pos, key, od ); 
                    

                    // ar.WriteObject(&od);
                    ar << &od;
                    }

                    Executes for loop 2 times, od has respectives values i.e. "Two" followed by "One". In my text file, I can see only "Two":

                     ÿÿ
                     OperatorDetails Two

                    While Reading:

                    		OperatorDetails\* od;
                    	
                    	for (int i=0; i < count; i++) {
                    		OperatorDetails odObj;
                    		ar >> od;
                    		if (od == NULL)
                    			break;
                    		
                    		odObj.SetOperatorNo(od->GetOperatorNo());
                    		odObj.SetOperName(od->GetOperName());
                    		operMap->SetAt(odObj.GetOperatorNo(), odObj);
                    	}
                    		delete od;
                    

                    For loop executes twice as count is stored as 2 records while writing. Both the times it gets only "Two". So number of records actually retrieved are only 1 as the key is the same 2. While writing though &od has the proper object 2nd time i.e. 1 One, still it doesn't write only. ar << &od is also executing properly, still somehow something is acting weird. Can you help me figure out that improper stuff. Would be glad enough & able to take a relaxed breath.

                    Thanks Terry

                    M Offline
                    M Offline
                    Mark Salsbery
                    wrote on last edited by
                    #10

                    Trupti Mehta wrote:

                    for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL [Wink] { int key; OperatorDetails od; opdtMap.GetNextAssoc(pos, key, od ); // ar.WriteObject(&od); ar << &od; }

                    I tested this and traced into the MFC code to see why only one object was getting written to the archive. There's an "optimization" in there - if the CObject* serialized with WriteObject() (or ar << &od;, which calls WriteObject()) matches a CObject* that's already been written to the archive, then just a reference to the original serialized object is written to the archive. Since the above code is passing the same pointer (a pointer to the same object) each time, the first object found gets serialized, then only references to that first object are written. FWIW, here's an example of the correct way to serialize/unserialize a CMap:

                    typedef CMap<int, int, OperatorDetails, OperatorDetails&> OperatorDetailsMap;

                    template <> void AFXAPI SerializeElements <OperatorDetails> (CArchive &ar, OperatorDetails *pOperatorDetails, INT_PTR nCount)
                    {
                    for (int i = 0; i < nCount; i++, pOperatorDetails++)
                    {
                    pOperatorDetails->Serialize(ar);
                    }
                    }

                    void WriteArchive()
                    {
                    OperatorDetailsMap newOperMap;
                    newOperMap.SetAt(1, OperatorDetails(1, _T("One")));
                    newOperMap.SetAt(2, OperatorDetails(2, _T("Two")));

                    CFile myfile(\_T("e:\\\\archive\_test.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite);
                    CArchive ar(&myfile, CArchive::store);   
                    
                    newOperMap.Serialize(ar);
                    
                    ar.Close();
                    myfile.Close();
                    

                    }

                    void ReadArchive()
                    {
                    OperatorDetailsMap newOperMap;

                    CFile myfile(\_T("e:\\\\archive\_test.txt"), CFile::modeRead | CFile::shareDenyNone);
                    CArchive ar(&myfile, CArchive::load);   
                    
                    newOperMap.Serialize(ar);
                    
                    ar.Close();
                    myfile.Close();
                    

                    }

                    Mark Salsbery Microsoft MVP - Visual C++ :java:

                    T 1 Reply Last reply
                    0
                    • M Mark Salsbery

                      Trupti Mehta wrote:

                      for (POSITION pos = opdtMap.GetStartPosition(); pos != NULL [Wink] { int key; OperatorDetails od; opdtMap.GetNextAssoc(pos, key, od ); // ar.WriteObject(&od); ar << &od; }

                      I tested this and traced into the MFC code to see why only one object was getting written to the archive. There's an "optimization" in there - if the CObject* serialized with WriteObject() (or ar << &od;, which calls WriteObject()) matches a CObject* that's already been written to the archive, then just a reference to the original serialized object is written to the archive. Since the above code is passing the same pointer (a pointer to the same object) each time, the first object found gets serialized, then only references to that first object are written. FWIW, here's an example of the correct way to serialize/unserialize a CMap:

                      typedef CMap<int, int, OperatorDetails, OperatorDetails&> OperatorDetailsMap;

                      template <> void AFXAPI SerializeElements <OperatorDetails> (CArchive &ar, OperatorDetails *pOperatorDetails, INT_PTR nCount)
                      {
                      for (int i = 0; i < nCount; i++, pOperatorDetails++)
                      {
                      pOperatorDetails->Serialize(ar);
                      }
                      }

                      void WriteArchive()
                      {
                      OperatorDetailsMap newOperMap;
                      newOperMap.SetAt(1, OperatorDetails(1, _T("One")));
                      newOperMap.SetAt(2, OperatorDetails(2, _T("Two")));

                      CFile myfile(\_T("e:\\\\archive\_test.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite);
                      CArchive ar(&myfile, CArchive::store);   
                      
                      newOperMap.Serialize(ar);
                      
                      ar.Close();
                      myfile.Close();
                      

                      }

                      void ReadArchive()
                      {
                      OperatorDetailsMap newOperMap;

                      CFile myfile(\_T("e:\\\\archive\_test.txt"), CFile::modeRead | CFile::shareDenyNone);
                      CArchive ar(&myfile, CArchive::load);   
                      
                      newOperMap.Serialize(ar);
                      
                      ar.Close();
                      myfile.Close();
                      

                      }

                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                      T Offline
                      T Offline
                      Trupti Mehta
                      wrote on last edited by
                      #11

                      tHANKS mARK. I appreciate your efforts and help towards my problem. The above code works perfectly with Visual Studio. But when I added in eVC++, I am getting Linker errors. Code is added & implemented in the same way in VS & eVC++. I added the above code in my DbOperations class - SerializeElements is not a member of DbOperations, just added in the class cpp file. And from another dialog class Operator, I am calling db.WriteArchive() & ReadArchive(). From my view class, via a menu Operator.doModal is called, so view class is also in the picture. I get the following errors:

                      Linking...
                      MC_AppView.obj : error LNK2005: "void __cdecl SerializeElements(class CArchive &,class OperatorDetails *,int)" (?SerializeElements@@YAXAAVCArchive@@PAVOperatorDetails@@H@Z) already defined in DbOperations.obj
                      Operator.obj : error LNK2005: "void __cdecl SerializeElements(class CArchive &,class OperatorDetails *,int)" (?SerializeElements@@YAXAAVCArchive@@PAVOperatorDetails@@H@Z) already defined in DbOperations.obj
                      ARMV4IDbg/MC_App.exe : fatal error LNK1169: one or more multiply defined symbols found
                      Error executing link.exe.

                      I tried making SerializeElemnets as a member of DbOperations, but that also gives lots of errors due to <>, etc. How do I avoid these errors?

                      Thanks Terry

                      T 1 Reply Last reply
                      0
                      • T ThatsAlok

                        just a question are ATL header files are available for eVC, you could use CAtlFile Class [^]

                        T Offline
                        T Offline
                        Trupti Mehta
                        wrote on last edited by
                        #12

                        No Alok, ATL is not available in eVC, only MFC & pure C/C++. In that too with Win CE, many are again not allowed or supported.

                        Thanks Terry

                        1 Reply Last reply
                        0
                        • M Mark Salsbery

                          First, I would change the CMap ARG_KEY and ARG_VALUE types to references:

                          CMap<int, int&, OperatorDetails, OperatorDetails&>

                          Second, can you post the OperatorDetails::Serialize() code? Mark

                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                          T Offline
                          T Offline
                          Trupti Mehta
                          wrote on last edited by
                          #13

                          My Serialize code is :

                          // Serialize
                          void OperatorDetails::Serialize(CArchive &ar)
                          {
                          if (ar.IsStoring())
                          ar << operNo << operName;
                          else
                          ar >> operNo >> operName;

                          }

                          And the linker error says (the part that is cut for view.obj & Operator.obj) already defined in DbOperations.obj

                          Thanks Terry

                          1 Reply Last reply
                          0
                          • T Trupti Mehta

                            tHANKS mARK. I appreciate your efforts and help towards my problem. The above code works perfectly with Visual Studio. But when I added in eVC++, I am getting Linker errors. Code is added & implemented in the same way in VS & eVC++. I added the above code in my DbOperations class - SerializeElements is not a member of DbOperations, just added in the class cpp file. And from another dialog class Operator, I am calling db.WriteArchive() & ReadArchive(). From my view class, via a menu Operator.doModal is called, so view class is also in the picture. I get the following errors:

                            Linking...
                            MC_AppView.obj : error LNK2005: "void __cdecl SerializeElements(class CArchive &,class OperatorDetails *,int)" (?SerializeElements@@YAXAAVCArchive@@PAVOperatorDetails@@H@Z) already defined in DbOperations.obj
                            Operator.obj : error LNK2005: "void __cdecl SerializeElements(class CArchive &,class OperatorDetails *,int)" (?SerializeElements@@YAXAAVCArchive@@PAVOperatorDetails@@H@Z) already defined in DbOperations.obj
                            ARMV4IDbg/MC_App.exe : fatal error LNK1169: one or more multiply defined symbols found
                            Error executing link.exe.

                            I tried making SerializeElemnets as a member of DbOperations, but that also gives lots of errors due to <>, etc. How do I avoid these errors?

                            Thanks Terry

                            T Offline
                            T Offline
                            Trupti Mehta
                            wrote on last edited by
                            #14

                            Mark, I removed the template <> SerializeElements() from the code & ran the application. Its still running and giving the results as we expected, but after reading is completed, it throws Assertion Failure: on strcode.cpp Line 171 which falls under void CString::Release(), ASSERT(GetData()->nRefs != 0); line. If I do retry, it works properly. I need to get rid of this error. Do you know how to I catch exception in eVC++. If I write try{ .... } catch(CException e) { } it shows warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX. The MSDN warning lists of 4530 mentions to specify /EHsc. How do I speicify any of this & where in the Project Settings. This will be a great help, as I like very much to catch exception and handle them. But in eVC I am not able to do it due to these errors/warnings. Please would be nice if can help out in this.

                            Thanks Terry

                            M 1 Reply Last reply
                            0
                            • T Trupti Mehta

                              Mark, I removed the template <> SerializeElements() from the code & ran the application. Its still running and giving the results as we expected, but after reading is completed, it throws Assertion Failure: on strcode.cpp Line 171 which falls under void CString::Release(), ASSERT(GetData()->nRefs != 0); line. If I do retry, it works properly. I need to get rid of this error. Do you know how to I catch exception in eVC++. If I write try{ .... } catch(CException e) { } it shows warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX. The MSDN warning lists of 4530 mentions to specify /EHsc. How do I speicify any of this & where in the Project Settings. This will be a great help, as I like very much to catch exception and handle them. But in eVC I am not able to do it due to these errors/warnings. Please would be nice if can help out in this.

                              Thanks Terry

                              M Offline
                              M Offline
                              Mark Salsbery
                              wrote on last edited by
                              #15

                              Trupti Mehta wrote:

                              I removed the template <> SerializeElements() from the code & ran the application. Its still running and giving the results as we expected,

                              That won't work well with CStrings in the OperatorDetails class, since without a SerializeElements() override for the CMap, the default serialization of the map's objects is binary bits - not good when pointers are involved :) I'm not sure why the template function causes the link to fail.  You should be able to put the SerializeElements() template in ONE cpp file and it should work.  I tested with it in the same CPP file that does the serialization/unserialization of the CMap (just above my sample WriteArchive() and ReadArchive functions). Mark

                              Mark Salsbery Microsoft MVP - Visual C++ :java:

                              T 1 Reply Last reply
                              0
                              • M Mark Salsbery

                                Trupti Mehta wrote:

                                I removed the template <> SerializeElements() from the code & ran the application. Its still running and giving the results as we expected,

                                That won't work well with CStrings in the OperatorDetails class, since without a SerializeElements() override for the CMap, the default serialization of the map's objects is binary bits - not good when pointers are involved :) I'm not sure why the template function causes the link to fail.  You should be able to put the SerializeElements() template in ONE cpp file and it should work.  I tested with it in the same CPP file that does the serialization/unserialization of the CMap (just above my sample WriteArchive() and ReadArchive functions). Mark

                                Mark Salsbery Microsoft MVP - Visual C++ :java:

                                T Offline
                                T Offline
                                Trupti Mehta
                                wrote on last edited by
                                #16

                                Mark, I also have added in the same file (DbOperations.cpp) just copied your code same way. All serialization.desera & template overrride are in the same file. I tried removing template<> & AFXAPI, but still no success. You were very correct that with pointers of Map I will have a problem. To pass the DbOperations reference to other classes, I made a copy constructor & operator=, in this case I can't directly copy map tp map. So I made operatorMap as pointer & the other map deptMap is as a normal object only & not assigning in copy constru or =. deptMap additions & updations are possible (NOT a pointer), but operatorMap (a POINTER) operations are not allowed. It causes Assertion failure in afxtempl.h line 1368 which is Assert 1st line of CMap<> operator[]. I got to take out some solution of this. Can you tell how to assign a map to map in copy constructr & = operator. Basically copy a map to other. In DbOperations .h

                                typedef CMap<int, int, OperatorDetails, OperatorDetails&> OperatorDetailsMap;
                                typedef CMap<int, int, DeptDetails, DeptDetails&> DeptDetailsMap;

                                class ....{
                                // MAPS
                                OperatorDetailsMap* operMap;
                                DeptDetailsMap deptMap;

                                In .cpp
                                // Copy Constructor
                                DbOperations::DbOperations(const DbOperations &d) {
                                this->operMap = d.operMap;
                                // this->deptMap = d.deptMap;
                                }
                                // = Assignment operator
                                DbOperations& DbOperations::operator=(const DbOperations &d) {
                                this->operMap = d.operMap;
                                // this->deptMap = d.deptMap;

                                return \*this;
                                

                                }
                                /*template <> void AFXAPI SerializeElements <OperatorDetails> (CArchive &ar, OperatorDetails *pOperatorDetails, INT_PTR nCount){
                                for (int i = 0; i < nCount; i++, pOperatorDetails++) {
                                pOperatorDetails->Serialize(ar);
                                }
                                }*/

                                My point is how do I copy this.deptMap with d.deptMap, where deptMap being normal objects & not a pointer. With this solution we wont have problem with serializeElements() & pointers. As SerializeElements() causes problems, so looking out for solution without serializeElements & pointers. SerializeElemtsis added only in DbOperations along with WriteArchive & ReadArchive. The same thing is working with Visual Studio, but not with eVC++4. Really it is difficult to code in eVC++ than VC++, many restrictions & uncompatibility. Looking for solution as soon as possible. From days I have been looking for this solution & yet not solved. You have been extremely helpful throughout. I highly appreciate your help and look towards more help. <

                                1 Reply Last reply
                                0
                                Reply
                                • Reply as topic
                                Log in to reply
                                • Oldest to Newest
                                • Newest to Oldest
                                • Most Votes


                                • Login

                                • Don't have an account? Register

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • World
                                • Users
                                • Groups