Using RAPI to Find Remote Files
Our tool for retrieving information about files on the CE device is the powerhouse function, CeFindAllFiles(). CeFindAllFiles() has no analog on the CE side. It is specifically designed for RAPI applications, and retrieves all the files and folders under a particular node, in a single call. This is advantageous because it is much more efficient for the CE side than enumerating files and folders individually, and for this reason saves both processing time and battery power.
The arguments to the function are: a pointer to a Unicode string specifying a DOS style search path, a DWORD containg flags that determine what file attributes to return, a count of the returned items, and the address of a pointer of type LPCE_FIND_DATA. On successful return, the last parameter contains the address of an array of CE_FIND_DATA structures. Here is the typedef for CE_FIND_DATA:
typedef struct _CE_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; //0, unless the overall file size is > //MAXDWORD DWORD nFileSizeLow; //file size in bytes DWORD dwOID; //CE Object Identifier for this file WCHAR cFileName[MAX_PATH]; //Unicode file name } CE_FIND_DATA;
Based on the state of the checkbox controls, we add flags to dwFileAttributeFlags. At a minimum, we'll retrieve the filename, and optionally the creation time, last write time, and CE Object ID for the file. If the GetFoldersOnly box is checked, we retrieve information for all the folders in the search path and skip over the files. Here's a complete list of the CE_FIND_DATA () file attribute flags, along with their meanings.
Table 1: CE_FIND_DATA File Attribute Flags And Their Meanings
File Attribute Flag Name | Meaning |
FAF_ATTRIB_CHILDREN | Only retrieve information for directories with child items |
FAF_ATTRIB_NO_HIDDEN | Omit files or directories that have the hidden attribute set |
FAF_FOLDERS_ONLY | Retrieve information for directories only |
FAF_NO_HIDDEN_SYS_ROMMODULES | Omit ROM files or directories |
FAF_ATTRIBUTES | Return file attributes in dwFileAttributes |
FAF_CREATION_TIME | Return file creation time in ftCreationTime |
FAF_LASTACCESS_TIME | Return last access time in ftLastAccessTime |
FAF_LASTWRITE_TIME | Return last write time in ftLastWriteTime |
FAF_SIZE_HIGH | Return the high-order DWORD value of the file size in nFileSizeHigh |
FAF_SIZE_LOW | Return the low-order DWORD value of the file size in nFileSizeLow |
FAF_OID | Return the CE object identifier of the file in dwOID |
FAF_NAME | Return the Unicode file name in cFileName |
DWORD dwFileAttributeFlags = FAF_NAME; if( m_GetCreationTime.GetCheck() ) { dwFileAttributeFlags |= FAF_CREATION_TIME ; } if( m_GetLastWriteTime.GetCheck() ) { dwFileAttributeFlags |= FAF_LASTWRITE_TIME ; } if( m_GetFoldersOnly.GetCheck() ) { dwFileAttributeFlags |= FAF_FOLDERS_ONLY; } if( m_GetCEOID.GetCheck() ) { dwFileAttributeFlags |= FAF_OID; } BOOL bOk = CeFindAllFiles( (LPCWSTR)&wszFileName[0], dwFileAttributeFlags, &dwFoundCount, &pFindDataArray ); if(!bOk ) { return; }
On successful return for CeFindAllFiles, we loop through the array of returned structures, transferring the retrieved information to the list control, m_FilesList. Notice that we use the count of found items, dwFoundCount, returned by CeFindAllFiles to set the loop limit. Because the returned file name is a Unicode string, we must translate it to multi byte character format by using wcstombs() before attempting to insert it into the list control.
char szLineBuff[MAX_PATH]; for( int i = 0; i < dwFoundCount; i++ ) { wcstombs( szLineBuff, pFindDataArray[i].cFileName, sizeof(szLineBuff)); m_FilesList.InsertString( -1, szLineBuff ); if( m_GetCreationTime.GetCheck() ) { CTime FileCreationTime(pFindDataArray[i].ftCreationTime, -1 ); CString csBuff = FileCreationTime.Format("%A, %B %d, %Y" ); sprintf( szLineBuff, " %s: %s", "Creation Time", csBuff.GetBuffer(csBuff.GetLength()) ); m_FilesList.InsertString( -1, szLineBuff ); } if( m_GetLastWriteTime.GetCheck() ) { CTime LastWriteTime(pFindDataArray[i].ftCreationTime, -1 ); CString csBuff = LastWriteTime.Format("%A, %B %d, %Y" ); sprintf( szLineBuff, " %s: %s", "Last Write", csBuff.GetBuffer(csBuff.GetLength()) ); m_FilesList.InsertString( -1, szLineBuff ); } if( m_GetCEOID.GetCheck() ) { sprintf( szLineBuff, " %s: %s%x", "CEOID", "0x", pFindDataArray[i].dwOID ); m_FilesList.InsertString( -1, szLineBuff ); } // m_FilesList.InsertString( -1, " " ); }//end for()
Notice that our call to CeFindAllFiles() returned a pointer to a dynamically allocated array of CE_FIND_DATA structures. We must free this buffer that was allocated in our behalf before we uninitialize the RAPI subsystem, or memory will be "leaked."
//free the CE_FIND_DATA structure array buffer hr = CeRapiFreeBuffer((LPVOID) pFindDataArray); //now uninitialize RAPI. CeRapiUninit(); }
Looking Ahead
In our next lesson, we'll learn how to remotely walk the CE side Registry tree, a very useful technique for remotely managing CE side configurations.
About the Author
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, she has written several books, including Making Win 32 Applications Mobile.
# # #
Page 2 of 2
This article was originally published on July 26, 2004