Copying Files from the Device to the Desktop using .NET
Recently, I’ve been working on a tool that creates a backup of a SQL Server Compact Edition database on the device to the desktop. To accomplish this, I used the Remote API (RAPI). Unfortunately, the Remote API is not yet available in managed code. In this article I would like to demonstrate how to P/Invoke methods from the Remote API for copying files from the device to the desktop using managed code.
First, we’ll need some P/Invokes to rapi.dll
[DllImport("rapi.dll")]
static extern int CeRapiInit();
[DllImport("rapi.dll")]
static extern int CeRapiUninit();
[DllImport("rapi.dll")]
static extern int CeCloseHandle(IntPtr hObject);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern IntPtr CeCreateFile(
string lpFileName,
uint dwDesiredAccess,
int dwShareMode,
int lpSecurityAttributes,
int dwCreationDisposition,
int dwFlagsAndAttributes,
int hTemplateFile);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
static extern int CeReadFile(
IntPtr hFile,
byte[] lpBuffer,
int nNumberOfbytesToRead,
ref int lpNumberOfbytesRead,
int lpOverlapped);
const int ERROR_SUCCESS = 0;
const int OPEN_EXISTING = 3;
const int INVALID_HANDLE_VALUE = -1;
const int FILE_ATTRIBUTE_NORMAL = 0x80;
const uint GENERIC_READ = 0x80000000;
Now let’s create a method called CopyFromDevice(string remote_file, string local_file). The remote_file parameter is the source file on the device that you wish to copy. The local_file parameter is the destination filename on the desktop.
public static void CopyFromDevice(string remote_file, string local_file)
{
bool rapi = CeRapiInit() == ERROR_SUCCESS;
if (!rapi) {
return;
}
IntPtr remote_file_ptr = CeCreateFile(
remote_file,
GENERIC_READ,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (remote_file_ptr.ToInt32() == INVALID_HANDLE_VALUE) {
return;
}
FileStream local_file_stream = new FileStream(
local_file,
FileMode.Create,
FileAccess.Write);
int read = 0;
int size = 1024 * 4;
byte[] data = new byte[size];
CeReadFile(remote_file_ptr, data, size, ref read, 0);
while (read > 0) {
local_file_stream.Write(data, 0, read);
if (CeReadFile(remote_file_ptr, data, size, ref read, 0) == 0)
{
CeCloseHandle(remote_file_ptr);
local_file_stream.Close();
return;
}
}
CeCloseHandle(remote_file_ptr);
local_file_stream.Flush();
local_file_stream.Close();
if (rapi) {
CeRapiUninit();
}
if (!File.Exists(local_file)) {
throw new FileNotFoundException("The file was not copied to the desktop");
}
}
To use the code above you will have to know the full path of the file on the device. The way I did it was to read the registry on the device and check if my application was installed, if it was then I get the path of the application and pass as the path in my remote_file parameter.