Microsoft KB Archive/307256

= How to copy files to a Windows CE-based device by using RAPI from Visual Basic =

Article ID: 307256

Article Last Modified on 12/27/2004

-

APPLIES TO


 * Microsoft eMbedded Visual Basic 3.0
 * Microsoft Visual Basic 6.0 Professional Edition
 * Microsoft Visual Basic 6.0 Enterprise Edition

-



This article was previously published under Q307256



SUMMARY
This article discusses how to use the Remote API (RAPI) from Visual Basic to connect to a Windows CE-based device and to copy files between the device and the desktop.



Step-by-step example
 Start a new Standard EXE project in Visual Basic. By default, a form that is named Form1 is created. Add the following controls to the Form1 form. Do not be concerned about the placement of these controls.  Five command button controls. Six label controls. Four text box controls. One common dialog control.</ul> </li>  Paste the following code into the Form1 form. Private Sub Form_Load ConfigureUI Form1.Caption = &quot;RAPI File Copier&quot; Command1.Caption = &quot;Connect&quot; Command2.Caption = &quot;Disconnect&quot; Command2.Enabled = False Label1.Caption = &quot;PC File:&quot; Label2.Caption = &quot;Path/File Name on device:&quot; Text1.Text = &quot;C:\PCTestFile1.Txt&quot; Text2.Text = &quot;\CETestFile1.Txt&quot; Command3.Caption = &quot;Copy Down To Device&quot; Command5.Caption = &quot;...&quot; Label3.Caption = &quot;Device File:&quot; Label4.Caption = &quot;Path/File Name on PC:&quot; Text3.Text = &quot;\CETestFile1.Txt&quot; Text4.Text = &quot;C:\PCTestFile2.Txt&quot; Command4.Caption = &quot;Copy Up To Desktop&quot; Label5.Caption = &quot;Status: Disconnected!&quot; Label6.Caption = &quot;Bytes Copied: 0&quot; End Sub

Private Sub Form_Unload(Cancel As Integer) Command2_Click Unload Me End Sub

Private Sub Command1_Click 'Connect If RapiConnect Then Label5.Caption = &quot;Status: Connected!&quot; Command1.Enabled = False Command2.Enabled = True Else Label5.Caption = &quot;Status: Disconnected!&quot; Command1.Enabled = True Command2.Enabled = False End If End Sub

Private Sub Command2_Click 'Disconnect Call RapiDisconnect If RapiIsConnected Then Label5.Caption = &quot;Status: Connected!&quot; Command1.Enabled = False Command2.Enabled = True Else Label5.Caption = &quot;Status: Disconnected!&quot; Command1.Enabled = True Command2.Enabled = False End If End Sub

Private Sub Command3_Click If Not RapiIsConnected Then MsgBox &quot;Device is not connected. Please connect first.&quot; Exit Sub End If   If Not FileExists(Text1.Text) Then MsgBox &quot;The PC file could not be found.&quot;, vbInformation Exit Sub End If   Text1.Refresh Text2.Refresh Call RAPICopyPCFileToCE(Text1.Text, Text2.Text) End Sub

Private Sub Command4_Click If Not RapiIsConnected Then MsgBox &quot;Device is not connected. Please connect first.&quot; Exit Sub End If   If FileExists(Text4.Text) Then MsgBox &quot;The PC file already exists. It will NOT be overwritten!&quot; Exit Sub End If   Text3.Refresh Text4.Refresh Call RAPICopyCEFileToPC(Text3.Text, Text4.Text) End Sub

Private Sub Command5_Click CommonDialog1.ShowOpen If CommonDialog1.FileName = &quot;&quot; Then Exit Sub Text1.Text = CommonDialog1.FileName Text2.Text = Mid(Text1.Text, InStrRev(Text1.Text, &quot;\&quot;), _       Len(Text1.Text)) Text3.Text = Text2.Text Text4.Text = Mid(Text1.Text, 1, InStrRev(Text1.Text, &quot;.&quot;) - 1) _ & &quot;2&quot; & Mid(Text1.Text, InStrRev(Text1.Text, &quot;.&quot;), Len(Text1.Text)) End Sub

Private Sub ConfigureUI Form1.Move 345, 465, 10410, 3675 Command1.Move 120, 120, 4935, 750 Command2.Move 5220, 120, 4935, 750 Command3.Move 8040, 1020, 2115, 750 Command4.Move 8040, 1995, 2115, 750 Command5.Move 7620, 1020, 295, 285 Label1.Move 120, 1020, 915, 255 Label2.Move 120, 1440, 1895, 255 Label3.Move 120, 1995, 915, 255 Label4.Move 120, 2415, 1895, 255 Label5.Move 120, 2940, 4935, 255 Label6.Move 5220, 2940, 4935, 255 Text1.Move 1140, 1020, 6375, 285 Text2.Move 2085, 1440, 5790, 285 Text3.Move 1140, 1995, 6735, 285 Text4.Move 2085, 2415, 5790, 285 End Sub </li> On the Project menu, click Add Module to add a new module to the project.</li>  Paste the following code into the Module1 module. Option Explicit Private Declare Function WaitForSingleObject Lib &quot;kernel32&quot; ( ByVal _ hHandle As Long   ByVal dwMilliseconds As Long) As Long

Public Const ONE_SECOND = 1000 Public Const E_FAIL = &H80004005

Public Const FILE_ATTRIBUTE_NORMAL = &H80

Public Const INVALID_HANDLE_VALUE = -1

Public Const GENERIC_READ = &H80000000 Public Const GENERIC_WRITE = &H40000000

Public Const CREATE_NEW = 1 Public Const CREATE_ALWAYS = 2 Public Const OPEN_EXISTING = 3

Public Const ERROR_FILE_EXISTS = 80 Public Const ERROR_INVALID_PARAMETER = 87 Public Const ERROR_DISK_FULL = 112

Public Type CEOSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long szCSDVersion As String * 128 End Type

Public Type RAPIINIT cbSize As Long heRapiInit As Long hrRapiInit As Long End Type

Public Type SECURITY_ATTRIBUTES nLength As Long lpSecurityDescriptor As Long bInheritHandle As Boolean End Type

Public Type MyType value As Integer End Type

Public Declare Function CeCloseHandle Lib &quot;rapi.dll&quot; ( _   ByVal hObject As Long) As Boolean Public Declare Function CeCreateFile Lib &quot;rapi.dll&quot; ( _   ByVal lpFileName As String, _    ByVal dwDesiredAccess As Long, _    ByVal dwShareMode As Long, _    lpSecurityAttributes As SECURITY_ATTRIBUTES, _    ByVal dwCreationDistribution As Long, _    ByVal dwFlagsAndAttributes As Long, _    ByVal hTemplateFile As Long) As Long Public Declare Function CeGetVersionEx Lib &quot;rapi.dll&quot; ( _   lpVersionInformation As CEOSVERSIONINFO) As Boolean Public Declare Function CeRapiInitEx Lib &quot;rapi.dll&quot; ( _   pRapiInit As RAPIINIT) As Long Public Declare Function CeRapiUninit Lib &quot;rapi.dll&quot; As Long

Public Declare Function CeReadFile Lib &quot;rapi.dll&quot; ( _   ByVal hFile As Long, _    lpBuffer As Any, _    ByVal nNumberOfBytesToRead As Long, _    lpNumberOfBytesRead As Long, _    ByVal lpOverlapped As Long) As Boolean Public Declare Function CeWriteFile Lib &quot;rapi.dll&quot; ( _   ByVal hFile As Long, _    lpBuffer As Any, _    ByVal nNumberOfBytesToWrite As Long, _    lpNumberOfBytesWritten As Long, _    ByVal lpOverlapped As Long) As Boolean Public Declare Function CeGetLastError Lib &quot;rapi.dll&quot; As Long

'Wrapper functions for above API calls

Private Function GetSub(Addr As Long) As Long 'Used for the init call. GetSub = Addr End Function

Public Sub ConnectedRapi 'Used for the init call. Do not remove. End Sub

Public Function RapiConnect As Boolean 'Initiates a connection and returns true ' if it connected, false if it did not. 'Modified to match suggestion of Microsoft KB article 831883 'http://support.microsoft.com/default.aspx?scid=kb;en-us;831883

Dim pRapiInit As RAPIINIT Dim dwWaitRet, dwTimeout As Long Dim hr As Long

On Error GoTo RapiConnect_Err pRapiInit.cbSize = Len(pRapiInit) pRapiInit.heRapiInit = 0 pRapiInit.hrRapiInit = 0

hr = E_FAIL dwWaitRet = 0 dwTimeout = 10 * ONE_SECOND 'However long you want to wait

'Call CeRapiInitEx one time. hr = CeRapiInitEx(pRapiInit) If hr < 0 Then 'FAILED GoTo Failed End If  'Wait for the RAPI event until timeout.

'Use the WaitForSingleObject function for the worker thread 'Use the WaitForMultipleObjects function if you are also waiting for other events. dwWaitRet = WaitForSingleObject(pRapiInit.heRapiInit, dwTimeout) If dwWaitRet = 0 Then 'WAIT_OBJECT_0 'If the RAPI init is returned, check result If pRapiInit.hrRapiInit >= 0 Then 'SUCCEEDED GoTo Succeeded Else GoTo Failed End If  Else 'Timeout or failed. GoTo Failed End If  'success Succeeded: 'Now you can make RAPI calls. RapiConnect = True Exit Function Failed: 'Uninitialize RAPI if you ever called CeRapiInitEx. If hr >= 0 Then 'SUCCEEDED Call CeRapiUninit End If  RapiConnect = False Exit Function RapiConnect_Err: RapiConnect = False End Function

Public Sub RAPICopyCEFileToPC(ByVal CESourceFile As String, _       ByVal PCDestFile As String) Dim lCeFileHandle  As Long Dim iFile          As Integer Dim BytePos        As Long Dim lBufferLen     As Long Dim lBytesRead     As Long Dim bytFile(2048)  As Byte Dim lResult        As Long Dim I              As Integer ' Open the CE file. lCeFileHandle = RapiOpenFile(CESourceFile, 1, False, _           FILE_ATTRIBUTE_NORMAL) If lCeFileHandle <> INVALID_HANDLE_VALUE Then 'Create a file on the PC and write ' the bytes from the CE file to it. iFile = FreeFile Open PCDestFile For Binary Access Write As iFile BytePos = 1 lBufferLen = 2048 Do           lResult = CeReadFile(lCeFileHandle, bytFile(0), _                    lBufferLen, lBytesRead, 0&) If (lResult And (lBytesRead = 0)) Then lResult = CeCloseHandle(lCeFileHandle) Close iFile Exit Do           Else For I = 0 To lBytesRead - 1 Put iFile, BytePos + I, bytFile(I) Next I               BytePos = BytePos + lBytesRead End If           Form1.Label6.Caption = &quot;Bytes Copied:&quot; & _ (BytePos - 1) & &quot; Up.&quot; Form1.Label6.Refresh Loop Form1.Label6.Caption = Form1.Label6.Caption & _ &quot; Transfer Completed.&quot; Else lResult = CeCloseHandle(lCeFileHandle) MsgBox &quot;Device File Does Not Exist Or Is Empty (0 Bytes)!&quot; End If End Sub

Public Sub RAPICopyPCFileToCE(ByVal PCSourceFile As String, _       ByVal CEDestFile As String) Dim iFile As Integer Dim bytFile As MyType Dim lCeFileHandle As Long Dim BytePos As Long Dim lBufferLen As Long Dim TotalCopied As Long Dim lBytesWritten As Long Dim lResult As Long 'Get bytes from PC file. iFile = FreeFile Open PCSourceFile For Binary Access Read As iFile ReDim bytFile(LOF(iFile)) Get iFile,, bytFile Close iFile 'Create a file on the CE Device and write ' the bytes from the PC file to it. lCeFileHandle = RapiOpenFile(CEDestFile, 2, _           True, FILE_ATTRIBUTE_NORMAL) If lCeFileHandle <> INVALID_HANDLE_VALUE Then BytePos = 0 'Copy this many bytes at a time (MUST BE EVEN #). lBufferLen = 2048 Do           If UBound(bytFile) - TotalCopied > lBufferLen Then ' Copy the next set of bytes lResult = CeWriteFile(lCeFileHandle, bytFile(BytePos), _                       lBufferLen, lBytesWritten, 0&) TotalCopied = TotalCopied + lBytesWritten ' Unicode compensation. BytePos = BytePos + (lBufferLen \ 2) Form1.Label6.Caption = &quot;Bytes Copied: &quot; & _ TotalCopied & &quot; Down.&quot; Form1.Label6.Refresh Else ' Copy the remaining bytes if greater than 0 lBufferLen = UBound(bytFile) - TotalCopied If lBufferLen > 0 Then ' Copy remaining bytes at one time. lResult = CeWriteFile(lCeFileHandle, _                          bytFile(BytePos), lBufferLen, lBytesWritten, 0&) End If               TotalCopied = TotalCopied + lBytesWritten Form1.Label6.Caption = &quot;Bytes Copied: &quot; & _ TotalCopied & &quot; Down.&quot; Form1.Label6.Refresh Exit Do           End If        Loop Else 'CeCreateFile failed. Why? Select Case CeGetLastError Case ERROR_FILE_EXISTS MsgBox &quot;A file already exists with the specified name.&quot; Case ERROR_INVALID_PARAMETER MsgBox &quot;A parameter was invalid.&quot; Case ERROR_DISK_FULL MsgBox &quot;Disk if Full.&quot; Case Else MsgBox &quot;An unknown error occurred.&quot; End Select End If   Form1.Label6.Caption = Form1.Label6.Caption & &quot; Transfer Completed.&quot; lResult = CeCloseHandle(lCeFileHandle) End Sub

Public Sub RapiDisconnect Call CeRapiUninit End Sub

Public Function RapiGetCEOSVersionString As String ' Returns the Major, Minor, and Build number of the OS In a string. Dim ceosver As CEOSVERSIONINFO ceosver.dwOSVersionInfoSize = Len(ceosver) If CeGetVersionEx(ceosver) Then RapiGetCEOSVersionString = ceosver.dwMajorVersion & &quot;.&quot; & _ ceosver.dwMinorVersion & &quot;.&quot; & _ ceosver.dwBuildNumber & &quot; &quot; & _ Left$(ceosver.szCSDVersion, _           InStr(ceosver.szCSDVersion, Chr$(0)) - 1) Else RapiGetCEOSVersionString = &quot;&quot; End If End Function

Public Function RapiIsConnected As Boolean ' Returns whether there is a RAPI connection. If the Version 'string is returned then we know we have a valid connection. RapiIsConnected = RapiGetCEOSVersionString <> &quot;&quot; End Function

Public Function RapiOpenFile(ByVal FileName As String, _       ByVal mode As Integer, _        ByVal CreateNew As Boolean, _        ByVal flags As Long) As Long Dim lReturn As Long Dim lFileMode As Long Dim Security As SECURITY_ATTRIBUTES Dim CreateDist As Long Select Case mode Case 1: lFileMode = GENERIC_READ Case 2: lFileMode = GENERIC_WRITE Case 3: lFileMode = GENERIC_READ Or GENERIC_WRITE End Select If CreateNew Then CreateDist = CREATE_NEW Else CreateDist = OPEN_EXISTING End If   lReturn = CeCreateFile(StrConv(FileName, vbUnicode), lFileMode, _            0, Security, CreateDist, flags, 0&) RapiOpenFile = lReturn End Function

Function FileExists(ByVal sFilename As String) As Boolean 'This function will check to make sure that a file exists. It will 'return True if the file was found and False if it was not found. 'Example: If Not FileExists(&quot;autoexec.bat&quot;) Then...

Dim I As Integer On Error Resume Next I = Len(Dir$(sFilename)) If Err Or I = 0 Or Trim(sFilename) = &quot;&quot; Then FileExists = False Else FileExists = True End If End Function </li> Run the project.</li> After you make sure that the Windows CE device is connected to the desktop computer through ActiveSync, click the Connect button.</li> Click the ellipsis button (...) to locate a file to send to the device, and then click Copy Down to Device. Notice that the file is copied to the device. However, if the file already exists on the device, the file that is already on the device is not overwritten.</li> Click Copy Up to Desktop. Notice that the file is copied to the desktop.</li></ol>

<div class="references_section">