/// <summary>
/// wince設備--pc有線通信類
/// </summary>
public class Rapi
{
private const int TimeOut = 2000;//異步連接設備超時時間2秒
#region 初始化、卸載設備(私有)
/// <summary>
/// 異步初始化設備,打開後不關閉(默認打開後不關閉,因此定義爲私有)
/// </summary>
/// <param name="nTimeout">單位ms</param>
/// <returns></returns>
private bool InitDevice(int nTimeout)
{
Rapiinit ri = new Rapiinit();
ri.cbsize = Marshal.SizeOf(ri);
uint hRes = CeRapiInitEx(ref ri);
ManualResetEvent me = new ManualResetEvent(false);
me.SafeWaitHandle = new SafeWaitHandle(ri.heRapiInit, false);
if (!me.WaitOne(nTimeout, true)) //阻塞等待結果
{
CeRapiUninit();
return false;
}
else
{
return true;
}
}
/// <summary>
/// CE設備卸載,一般情況下不適用,各個方法末尾已經卸載設備。
/// </summary>
private void RapiUninit()
{
CeRapiUninit();
}
#endregion
#region 公有方法(判斷文件是否存在、刪除、wince和pc傳輸文件)
/// <summary>
/// 判定文件是否存在
/// -1:連接不到服務器 0:不存在 1:存在
/// </summary>
/// <param name="fileName"></param>
/// <returns>-1:連接不到服務器 0:不存在 1:存在</returns>
public int IsExistFile(string fileName)
{
if (InitDevice(TimeOut))
{
CeFindData findData = new CeFindData();
int jieg = CeFindFirstFile(fileName, ref findData);
CeRapiUninit();
if (jieg != -1) return 1;
else return 0;
}
else
return -1;
}
/// <summary>
/// 刪除ce設備上的文件
/// -1:連接不到服務器 0:刪除失敗 1:刪除成功
/// </summary>
/// <param name="fileName">要刪除的文件名</param>
/// <returns>-1:連接不到服務器 0:刪除失敗 1:刪除成功</returns>
public int DeleteFile(string fileName)
{
if (InitDevice(TimeOut))
{
CeFindData findData = new CeFindData();
int jieg = CeFindFirstFile(fileName, ref findData);
if (jieg != -1)
{
bool isok = CeDeleteFile(fileName);
CeRapiUninit();
if (isok) return 1;
else return 0;
}
else return 1; //如果不存在要刪除的文件,等同於刪除成功。
}
else
return -1;
}
/// <summary>
/// PC-->Wince
/// </summary>
/// <param name="localFileName">pc文件</param>
/// <param name="remoteFileName">wince文件</param>
/// <returns></returns>
public bool CopyFileToPDA(string localFileName, string remoteFileName)
{
#region 方法用變量
const uint genericWrite = 0x40000000;
// 設置讀寫權限
const short createNew = 1;
// 創建新文件
const short fileAttributeNormal = 0x80;
// 設置文件屬性
const short invalidHandleValue = -1;
// 錯誤句柄
byte[] buffer = new byte[0x1000];
// 傳輸緩衝區定義爲4k
int byteswritten = 0;
int filepos = 0;
#endregion
if (InitDevice(TimeOut))
{
//查找遠程文件
CeFindData findData = new CeFindData();
int jieg = CeFindFirstFile(remoteFileName, ref findData);
if (jieg != -1)
{
CeDeleteFile(remoteFileName);
}
// 創建遠程文件
IntPtr remoteFile = CeCreateFile(remoteFileName, genericWrite, 0, 0, createNew, fileAttributeNormal, 0);
// 檢查文件是否創建成功
if ((int) remoteFile == invalidHandleValue)
{
throw new Exception("創建文件失敗!");
}
else
{
// 打開本地文件
FileStream localFile = new FileStream(localFileName, FileMode.Open);
// 讀取4K字節
int bytesread = localFile.Read(buffer, filepos, buffer.Length);
while (bytesread > 0)
{
// 移動文件指針到已讀取的位置
filepos += bytesread;
// 寫緩衝區數據到遠程設備文件
if (!Convert.ToBoolean(CeWriteFile(remoteFile, buffer, bytesread, ref byteswritten, 0)))
{
// 檢查是否成功,不成功關閉文件句柄,拋出異常
CeCloseHandle(remoteFile);
throw new Exception("寫遠程文件失敗!");
}
try
{
// 重新填充本地緩衝區
bytesread = localFile.Read(buffer, 0, buffer.Length);
}
catch (Exception)
{
bytesread = 0;
}
}
// 關閉本地文件
localFile.Close();
// 關閉遠程文件
CeCloseHandle(remoteFile);
CeRapiUninit();
return true;
}
}
else
{
return false;
}
}
/// <summary>
/// Wince-->Pc
/// </summary>
/// <param name="remoteFileName">wince文件</param>
/// <param name="localFileName">pc文件</param>
/// <returns> 1 成功 0 失敗 -1 沒找到文件</returns>
public int CopyFileToPC(string remoteFileName, string localFileName)
{
const short createOpen = 3;// 設置讀寫權限
const uint genericRead = 0x80000000;
const short fileAttributeNormal = 0x80; // 設置文件屬性
const short invalidHandleValue = -1; // 錯誤句柄
if (InitDevice(TimeOut))
{
IntPtr fileh = CeCreateFile(remoteFileName, genericRead, 0, 0, createOpen, fileAttributeNormal, 0);
if ((int) fileh == invalidHandleValue)
{
return -1;
}
else
{
try
{
FileStream writer = new FileStream(localFileName, FileMode.Create);
int size = CeGetFileSize((int) fileh, 0);
byte[] buff = new byte[400096];
int readed = 400096;
while (readed == 400096)
{
CeReadFile((int) fileh, buff, 400096, out readed, 0);
writer.Write(buff, 0, readed);
}
CeCloseHandle(fileh);
writer.Close();
//上傳成功後刪除ce文件
/*CeFindData findData = new CeFindData();
int jieg = CeFindFirstFile(remoteFileName, ref findData);
if (jieg != -1)
{
CeDeleteFile(remoteFileName);
}*/
CeRapiUninit();
return 1;
}
catch
{
return 0;
}
}
}
else
{
return 0;
}
}
#endregion
#region 該類要用到的結構體
public struct CeFindData
{
public int DwFileAttributes;
public FILETIME FtCreationTime;
public int FtCreationTime2;
public FILETIME FtLastAccessTime;
public FILETIME FtLastWriteTime;
public int NFileSizeHigh;
public int NFileSizeLow;
public int DwOid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string CFileName;
}
[StructLayout(LayoutKind.Explicit)]
private struct Rapiinit
{
[FieldOffset(0)] public int cbsize;
[FieldOffset(4)] public readonly IntPtr heRapiInit;
[FieldOffset(8)] private readonly IntPtr hrRapiInit;
}
#endregion
#region 聲明要引用的API
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeCloseHandle(IntPtr hObject);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeWriteFile(IntPtr hFile, byte[] lpBuffer,
int nNumberOfbytesToWrite, ref int lpNumberOfbytesWritten,
int lpOverlapped);
[DllImport("rapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr CeCreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode,
int lpSecurityAttributes, int dwCreationDisposition,
int dwFlagsAndAttributes, int hTemplateFile);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeRapiUninit();
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern bool CeDeleteFile(string fileName);
[DllImport("rapi.dll")]
private static extern uint CeRapiInitEx(ref Rapiinit pRapiInit);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeFindFirstFile(string lpFileName, ref CeFindData lpFindFileData);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeGetFileSize(int hFile, int lpOverlapped);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeReadFile(int hFile, byte[] lpBuffer, int lpOverlapped, out int laji, int gouride);
#endregion
#region 未用到的api接口
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
uint dwShareMode, IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern Boolean WriteFile(SafeFileHandle lpFileName, byte[] lpBuffer,
int nNumberOfbytesToWrite, ref int lpNumberOfbytesWritten,
int lpOverlapped);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeCopyFile(string lpExistingFileName, string lpNewFileName, Boolean bFailIfExists);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeReadFile(IntPtr hFile, byte[] lpBuffer,
int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, int lpOverlapped);
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeRapiInit();
[DllImport("rapi.dll", CharSet = CharSet.Unicode)]
private static extern int CeRapiGetError();
#endregion
}
在做WinCE和PC之間進行文件傳輸要用到rapi.dll,但是在xp和win7上是不同的移動設備中心,該動態庫的版本也是不同的,因此在VS解決方案中一定不要添加該動態庫,如果添加了一定不要輸出到debug裏面,否則會因爲編譯好的程序在不同的操作系統上出現問題,因爲目標平臺一定會安裝移動設備中心,程序會根據不同版本的rapi.dll動態的調用。
以上是在開發中遇到的問題。