Solved

Search, Read and Write to file.

Posted on 2004-08-17
23
302 Views
Last Modified: 2008-01-09
Question:

How do we Write to an external file and get the info on it using C++? The following source is seen below.
There is a problem more on the writing part as when after it is written to the external file and when its read, it only displays only the first letter of the word.

== Source Code ==

if (wcsstr(pspvEmail->Value.lpszW, L"98494778") != NULL)

      {
            MessageBeep(MB_ICONASTERISK);
            MessageBox(NULL, pspvSubject->Value.lpszW, pspvEmail->Value.lpszW, MB_OK);

            HANDLE hFile;
            const TCHAR* filename = TEXT("\\My Documents\\Personal\\jobs.txt"); // Name of file to be written
            const TCHAR* file_contents = pspvSubject->Value.lpszW; // String to be written to file
            TCHAR message[255]; // String to be displayed in message box
            DWORD bytesWritten;

            // Open existing file or create it if it does not exist
            hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

            if (hFile == INVALID_HANDLE_VALUE)
            MessageBox(NULL,TEXT("Couldn't create the file!"), TEXT("Create File ERROR"), MB_OK);
            else
            {

                  // Write a string to the file
                  if (WriteFile(hFile, file_contents , wcslen(file_contents)*sizeof(TCHAR), &bytesWritten, NULL)!=0)
                  {
                  wsprintf(message, TEXT("Success - String %s written to file %s."), file_contents, filename);
                  }
                  else
                  {
                  wsprintf(message, TEXT("Error writing to file: %d"), GetLastError());
                  }
            

            // Display the message indicating the result
            MessageBox(NULL, message, TEXT("Result"), MB_OK);

            // Close file handle
            CloseHandle(hFile);
            }
            
            // Delete the message and mark it as handled so it won't show up in Inbox
            hr = DeleteMessage(pMsgStore, pMsg, cbMsg, lpMsg, cbDestFolder, lpDestFolder, pulEventType, pHandled);
      }
      else
      {
            // a 'normal' message, pass it on
            *pHandled = MRC_NOT_HANDLED;      
      }

== End of Source Code ==
0
Comment
Question by:TPoly
  • 8
  • 8
  • 4
  • +1
23 Comments
 
LVL 13

Assisted Solution

by:SteH
SteH earned 50 total points
ID: 11818309
It seems that you are writing UNICODE text to the file. Is the application you are using able to display unicode or aware that this file is unicode. Most characters translate into the normal ASCII char plus a 0. A normal string read will terminate on that 0 displaing only the first char.
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 150 total points
ID: 11820104
Use WideCharToMultiByte function before writing to the file:

               int   wlen = wcslen(file_contents);
               char buf   = new char[wlen * 2 +1];  // should be enough
               // Write a string to the file
               int len = WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR, file_contents, wlen,
                                                            buf,  wlen * 2 +1, NULL, NULL);
               if (WriteFile(hFile, buf, &bytesWritten, NULL)!=0)
                 ...

Regards, Alex

0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 11820124
I forgot the len argument ...

        if (WriteFile(hFile, buf, len, &bytesWritten, NULL)!=0)
                 
0
 
LVL 19

Expert Comment

by:drichards
ID: 11825914
If you want to leave the file as UNICODE, you need to write the byte markers at the start of the file so a text editor will know it is UNICODE.  The bytes are 0xFFFE for 16-bit little-endian.  See

  http://www.unicode.org/unicode/faq/utf_bom.html#BOM

for more details.
0
 

Author Comment

by:TPoly
ID: 11827018
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_2bj9.asp

I've read on the above site and it indicate that its not safe to use the WideCharToMultiByte method due to security reasons.

== Quote from MSDN site ==

Remarks
 Security Alert   Using the WideCharToMultiByte function incorrectly can compromise the security of your application. Calling the WideCharToMultiByte function can easily cause a buffer overrun because the size of the In buffer equals the number of WCHARs in the string, while the size of the Out buffer equals the number of bytes.

== End of Quote ==

Actually I don't mind using any other code to write to a file. I can don't use the unicode. I need only any example that can show me on how to write to a file. Thanks.
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 150 total points
ID: 11827793
>>>> because the size of the In buffer equals the number of WCHARs in the string,
>>>> while the size of the Out buffer equals the number of bytes.

You could easily see that the OUT buffer from above has the same size as the IN buffer:

     char buf   = new char[wlen * 2 +1];  // should be enough

Furthermore, the size of the output buffer - wlen * 2 +1 -  correctly is passed to the WideCharToMultiByte function. So, you may not worry about buffer overrun when using the code above.

>> it only displays only the first letter of the word

When writing UNICODE strings to a text file, any second byte most likely is a binary zero character that - if shown using a 'normal' text editor - terminates the output string thus you'll see only the first character. So you should convert the string before writing as i told you above.

Regards, Alex

0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 150 total points
ID: 11828093
You may also use ATL conversion macros to convert UNICODE strings:

          ...
          if (hFile == INVALID_HANDLE_VALUE)
          MessageBox(NULL,TEXT("Couldn't create the file!"), TEXT("Create File ERROR"), MB_OK);
          else
          {
               USES_CONVERSION;

               LPSTR psz = W2A(pspvSubject->Value.lpszW);
               // Write a string to the file
               if (WriteFile(hFile, psz, strlen(psz)+1, &bytesWritten, NULL)!=0)
               {
               wsprintf(message, TEXT("Success - String %s written to file %s."), file_contents, filename);
               }
               else
               {
               wsprintf(message, TEXT("Error writing to file: %d"), GetLastError());
               }
         }

Regards, Alex
0
 

Author Comment

by:TPoly
ID: 11828189
This are the errors that was generated from the source code.
We are using Embedded Visual C++

== Error Generated ==

c:\documents and settings\tp\desktop\projfiles\mapirule 13-8\mapirule\mapirule.cpp(616) : error C2440: 'initializing' : cannot convert from 'char *' to 'char'
        This conversion requires a reinterpret_cast, a C-style cast or function-style cast
c:\documents and settings\tp\desktop\projfiles\mapirule 13-8\mapirule\mapirule.cpp(618) : error C2664: 'WideCharToMultiByte' : cannot convert parameter 5 from 'char' to 'char *'
        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
c:\documents and settings\tp\desktop\projfiles\mapirule 13-8\mapirule\mapirule.cpp(622) : error C2664: 'WriteFile' : cannot convert parameter 2 from 'char' to 'const void *'
        Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast

== End of Error ==
0
 
LVL 13

Expert Comment

by:SteH
ID: 11828218
This looks that at some point you try assign a char pointer to a char and at another you try to do the reverse. Check whether both need to be char* and change the variable type accordingly.
0
 
LVL 13

Expert Comment

by:SteH
ID: 11828221
Its in itsmeandnobodyelse's code:
               char buf   = new char[wlen * 2 +1];  // should be enough
should be
               char* buf   = new char[wlen * 2 +1];  // should be enough

and don't forget to delete[] that pointer after using it.

0
 

Author Comment

by:TPoly
ID: 11828346
Thanks for your fast reply..

There isn't any error now but the problem is that the output to the file is blank.
Nothing is written inside the file.


0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 11828489
STeH,

thanks for correcting my bugs ;-)


TPoly,

could you debug the function? Is there any value in pspvSubject->Value.lpszW or file_contents? What about buf? Is there any contents before WriteFile?

Regards, Alex
0
 

Author Comment

by:TPoly
ID: 11828565
== The codes from my question ==

// Write a string to the file
               if (WriteFile(hFile, file_contents , wcslen(file_contents)*sizeof(TCHAR), &bytesWritten, NULL)!=0)
               {
               wsprintf(message, TEXT("Success - String %s written to file %s."), file_contents, filename);
               }
               else
               {
               wsprintf(message, TEXT("Error writing to file: %d"), GetLastError());
               }

== End ==

The messagebox contains the value of file_contents.
And the file_contents has the value that we want (its a string).
example of what is inside file_contents: 123, 18/8/2004 13:45, 123,

I'm not quite sure about the buf. I don't know if there is anything contained inside the bluf.
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 11828616

>>>>          if (WriteFile(hFile, file_contents ,

writes the UNICODE string (buffer)  to file. When opening that with any text editor you only see the first character as explained above...

So you _HAVE_ to convert the file_contents buffer (it's a wide string where any character is a 16 bit short integer) to buf (that's a 'normal' string where any character is an 8 bit char) _AND_ use that 'buf' variable when calling WriteFile

    if (WriteFile(hFile, buf, strlen(buf) + 1,  ...

Regards, Alex
0
 
LVL 19

Expert Comment

by:drichards
ID: 11833170
>>    if (WriteFile(hFile, buf, strlen(buf) + 1,  ...

It's a text file so you should not write the string terminator - don't use +1 with strlen(buf).
0
 
LVL 39

Assisted Solution

by:itsmeandnobodyelse
itsmeandnobodyelse earned 150 total points
ID: 11833275
>> It's a text file so you should not write the string terminator - don't use +1 with strlen(buf).

That's true. Maybe you should print a line feed character instead of the terminating zero:

Either that way ...

   if (WriteFile(hFile, buf, strlen(buf),  ... ))
   {
         WriteFile(hFile, "\n", 1, ...);
         ...
   }

or like that:


   int len = strlen(buf);
   buf[len] = '\n';
   buf[++len] = '\0';

 
   if (WriteFile(hFile, buf, len,  ... ))
   {
         ...

Regards, Alex




0
 

Author Comment

by:TPoly
ID: 11837582
i tried using this method

=== alex's code===

   int len = strlen(buf);
   buf[len] = '\n';
   buf[++len] = '\0';

 
   if (WriteFile(hFile, buf, len,  ... ))
   {
         ...

===end===

now the result:
the contents of the is only a line feed...
0
 

Author Comment

by:TPoly
ID: 11837760
actually i had posted another question regarding passing a value from this compile dll(which is a dll trying to intercept the incoming SMS from the Inbox of a POCKET PC, so that the SMS is not handled by the Inbox) directly to an VB.NET application, however there is no reply for that question..

thus i try coding this dll and write the value into an external file (eg. jobs.txt) in a POCKET PC (the file format i tried are .pwi , .txt , .csv)..

jobs.txt act as a middleman between the dll and the VB.NET application...

thus at the VB.NET application side, it will reads the jobs.txt and gets the contents, use split() to break the string into parts and insert into a ListView object..

the above three components( dll, jobs.txt and VB.NET application) all resides in the POCKET PC...
0
 
LVL 19

Assisted Solution

by:drichards
drichards earned 300 total points
ID: 11837917
If you're trying to get this data into VB.NET in the end, you should just leave the data as UNICODE since that's what VB.NET will want anyway.  Then in VB.NET, use code something like this (I don't have my development machine to test at the moment to test):

        Dim aStreamReader As TextReader
        aStreamReader = New StreamReader("jobs.txt", System.Text.UnicodeEncoding, True)      
        Dim str As String = aStreamReader.ReadLine()

This should recover the UNICODE string from the file.  The True parameter in the StreamReader constructor tells it to automatically detect the encoding from the byte order marks at the beginning of the file.  If you don't write the marker bytes to the file (as I described previously), you should use False and it will just use the encoding you specify (I think - haven't tried it).
0
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 11838627
That sequence
     
     USES_CONVERSION;
     char* buf   = W2A(pspvSubject->Value.lpszW);

     int len = strlen(buf);
     buf[len] = '\n';
     buf[++len] = '\0';

     if (WriteFile(hFile, buf, len, &bytesWritten, NULL)!=0)
            ...

    ....

    CloseHandle(hFile);


should definitively give some valid output if

     pspvSubject->Value.lpszW

contains a UNICODE string (with printable characters) that isn't empty.

Did you check the values with the Debugger?

Regards, Alex
0
 
LVL 19

Accepted Solution

by:
drichards earned 300 total points
ID: 11841122
Had a chance to test this morning.  Need a change to param 2 of StreamReader constructor:

        Dim rdr As System.IO.TextReader = New System.IO.StreamReader("jobs.txt", System.Text.Encoding.Unicode, True)
        Dim txt As String = rdr.ReadLine()

It also works whether or not the marker bytes exist, so you should be able to use your original code which was writing the UNICODE string into the file and then use this VB code to read it back out.

0
 

Author Comment

by:TPoly
ID: 11848778
thanks for all your help...
learn alot man...
0
 

Author Comment

by:TPoly
ID: 11849180
i had posted another project related problem at this question title at VB.NET..

Question Title: Sending SMS to a GSM phone that is connected to a PC COM port

hope u guys can further help...

your help will be greatly appreciated...
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
This article shows you how to optimize memory allocations in C++ using placement new. Applicable especially to usecases dealing with creation of large number of objects. A brief on problem: Lets take example problem for simplicity: - I have a G…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

24 Experts available now in Live!

Get 1:1 Help Now