How the DesktopRapiInvoker Application Transfers the File

In this lesson, you'll see how the DesktopRapiInvoker application manages file transfers from the desktopside of a RAPI connection to a CE device. In the CMainFrame member OnDownloadHtml(), you choose a file to transfer to the desktop, initialize the RAPI subsystem, create and open a CE side file, and copy the desktop file to the CE side file.

The first step is to initialize and display the common file dialog to allow the user to choose a file for transfer. Note that this process of file selection is intentionally naïve. You don't use a filter string to ensure that the file is actually text or HTML, and you don't check to see whether the CE device has adequate space to accept the transferred file before you send it. In most real-world applications, it would be necessary to take these extra precautions. In this case, they are omitted for the sake of clarity and simplicity, but the techniques for performing these tasks are demonstrated in previous example programs in this series.

The Steps

You create an object of CfileDialog type, passing parameters to the constructor that customize the object for your purposes. Here are the parameters and what they do:

  • Setting the first parameter as TRUE indicates that you are opening rather than saving the file;
  • Setting the second parameter to NULL has the effect of preventing the appending of a default file extension to the name specified by the user;
  • The third parameter sets a flag that prevents read-only files from being displayed in the dialog;
  • The fourth parameter, set to NULL, means that you are not supplying a filter string to control the types of files displayed in the dialog;
  • And the final parameter is the handle to a window that can display error messages for the common file dialog if necessary.
void CMainFrame::OnDownloadHtml() 
{
   CString str1;

   CFileDialog dlg( TRUE, NULL, "",
                    OFN_HIDEREADONLY ,
                    NULL, this);

You can modify the appearance and behavior of the dialog by setting members of the OPENFILENAME structure before you actually invoke the dialog with a call to member function DoModal(). This structure is exposed by the CfileDialog class in the data member .m_ofn . In this case, you set the caption of the dialog by loading a string resource and setting dlg.m_ofn.lpstrTitle equal to the string object. Notice that you use _chdir() to set the initial directory to \My Documents. You also could have set this string in the m_ofn.lpstrInitialDir member.

   str1.LoadString( IDS_DOWNLOAD_DLG_CAPTION );
   dlg.m_ofn.lpstrTitle = str1;
   _chdir("\\My Documents" );

   CString str;
   CString strFileName;
   CFile fileHTML;

/* This is another way to set the initial directory for the dialog
   str.LoadString( IDS_DOWNLOAD_PATH );
   dlg.m_ofn.lpstrInitialDir = str.GetBuffer(str.GetLength());
*/

Next, youwe invoke the dialog, and, if it returns with IDOK, you get the filename the user has chosen. You open the file combining the flags for read only and binary access.

   if( dlg.DoModal() == IDOK )
      {
         strFileName = dlg.GetFileExt();
         strFileName = dlg.GetPathName();
         //open a stream file  
                
         if(    !fileHTML.Open( strFileName.GetBuffer(
                 strFileName.GetLength()), 
                 CFile::modeRead | CFile::typeBinary) )
         {
            str1.LoadString( IDS_ERR_FILE_OPEN );
            CWnd::MessageBox( str1, strFileName, MB_ICONHAND |
                              MB_OK );
            return;
         }

      }    //end if(dlg.DoModal() == IDOK )
else
{
   return;
}

Now, you are ready to copy the file to the CE device. First, you initialize the RAPI subsystem. You check the size of the file, allocate a buffer for it, and then read the entire file into memory on the desktop.

// open a file on the CE device
HRESULT hr = CeRapiInit();
if ( hr != ERROR_SUCCESS )
   { return; }

//how big is the desktop file
DWORD dwFileSize = fileHTML.GetLength();

//allocate a buffer
PBYTE pbFileBuff = (PBYTE) LocalAlloc(LPTR, dwFileSize);
if ( !pbFileBuff )
   {
      str1.LoadString( IDS_ALLOCATION_FAILURE );
      CWnd::MessageBox( str1, strFileName, MB_ICONHAND | MB_OK );
      return;
   }

//read it
fileHTML.Read(pbFileBuff, dwFileSize );

How the DesktopRapiInvoker Application Transfers the File

Now, you open a file on the CE device, in this case using the Unicode string MyHTMLViewerText as the file name. You open for both reading and writing, allow shared reading, pass a NULL placeholder for the unused security attributes parameter, set the CREATE_ALWAYS flag that creates the file if it doesn't exist or opens an existing file, clears all attributes, and zeroes the file length, sets default file attributes, and passes a NULL placeholder for the unused template handle parameter.

//open a CE side file
HANDLE hFile = CeCreateFile (L"MyHTMLViewerText",
                             GENERIC_READ | GENERIC_WRITE,
                             FILE_SHARE_READ, NULL, CREATE_ALWAYS,
                             FILE_ATTRIBUTE_NORMAL, NULL);

Next, you copy the file data from the buffer on the desktop to the CE side. You don't do any error checking in this example, but in practice, you'd want to check to see that dwBytesWritten and dwFileSize were equal after the call, and take some remedial action otherwise.

//copy from the desktop to the CE device
DWORD dwBytesWritten;
CeWriteFile( hFile, (LPCVOID)pbFileBuff,
             dwFileSize,    &dwBytesWritten, NULL);

Finally, you close the remote file, close the desktop file, and uninitialize the RAPI subsystem.

   //close both files
   CeCloseHandle( hFile );
   fileHTML.Close();

   //uninit rapi
   CeRapiUninit();


}

Summing Up and Looking Ahead

There are two or three things that are always worth keeping in mind when you undertake a mixed-platform CE application:

  • Make sure you keep a careful eye on string data and scrupulously ensure the use of the Unicode format for any displayable text on the CE device.
  • Be aware that serial CE connections can be very slow.
  • Assume that you will run into low memory and low storage situations. Program defensively and leave yourself a graceful bailout strategy if you get squeezed.

In the next lesson, you'll explore the mechanics of launching an HTML viewer on the CE device.



About the Author

Nancy Nicolaisen

Nancy Nicolaisen is a software engineer who has designed and implemented highly modular Windows CE products that include features such as full remote diagnostics, CE-side data compression, dynamically constructed user interface, automatic screen size detection, and entry time data validation. In addition to writing for Developer.com and CodeGuru, she has written several books, including Making Win 32 Applications Mobile.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

  • The hard facts on SaaS adoption in over 80,000 enterprises: Public vs. private companies Mid-market vs. large enterprise GoogleApps, Office365, Salesforce & more Why security is a growing concern Fill out the form to download the full cloud adoption report.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds