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



The information in this article applies to:

  • Microsoft eMbedded Visual Basic 3.0
  • Microsoft Visual Basic Professional Edition for Windows 6.0
  • Microsoft Visual Basic Enterprise Edition for Windows 6.0

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.

MORE INFORMATION

Step-by-step example

  1. Start a new Standard EXE project in Visual Basic. By default, a form that is named Form1 is created.
  2. 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.
  3. Paste the following code into the Form1 form.
    Private Sub Form_Load()
        ConfigureUI
        Form1.Caption = "RAPI File Copier"
        Command1.Caption = "Connect"
        Command2.Caption = "Disconnect"
        Command2.Enabled = False
        
        Label1.Caption = "PC File:"
        Label2.Caption = "Path/File Name on device:"
        Text1.Text = "C:\PCTestFile1.Txt"
        Text2.Text = "\CETestFile1.Txt"
        Command3.Caption = "Copy Down To Device"
        Command5.Caption = "..."
        
        Label3.Caption = "Device File:"
        Label4.Caption = "Path/File Name on PC:"
        Text3.Text = "\CETestFile1.Txt"
        Text4.Text = "C:\PCTestFile2.Txt"
        Command4.Caption = "Copy Up To Desktop"
        
        Label5.Caption = "Status: Disconnected!"
        Label6.Caption = "Bytes Copied: 0"
    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 = "Status: Connected!"
            Command1.Enabled = False
            Command2.Enabled = True
        Else
            Label5.Caption = "Status: Disconnected!"
            Command1.Enabled = True
            Command2.Enabled = False
        End If
    End Sub
    
    Private Sub Command2_Click()
        'Disconnect
        Call RapiDisconnect
        If RapiIsConnected Then
            Label5.Caption = "Status: Connected!"
            Command1.Enabled = False
            Command2.Enabled = True
        Else
            Label5.Caption = "Status: Disconnected!"
            Command1.Enabled = True
            Command2.Enabled = False
        End If
    End Sub
    
    Private Sub Command3_Click()
        If Not RapiIsConnected Then
            MsgBox "Device is not connected. Please connect first."
            Exit Sub
        End If
        If Not FileExists(Text1.Text) Then
            MsgBox "The PC file could not be found.", 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 "Device is not connected. Please connect first."
            Exit Sub
        End If
        If FileExists(Text4.Text) Then
            MsgBox "The PC file already exists. It will NOT be overwritten!"
            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 = "" Then Exit Sub
        Text1.Text = CommonDialog1.FileName
        Text2.Text = Mid(Text1.Text, InStrRev(Text1.Text, "\"), _
            Len(Text1.Text))
        Text3.Text = Text2.Text
        Text4.Text = Mid(Text1.Text, 1, InStrRev(Text1.Text, ".") - 1) _
            & "2" & Mid(Text1.Text, InStrRev(Text1.Text, "."), 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
    					
  4. On the Project menu, click Add Module to add a new module to the project.
  5. Paste the following code into the Module1 module.
    Option Explicit
    Private Declare Function WaitForSingleObject Lib "kernel32" (
      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 "rapi.dll" ( _
        ByVal hObject As Long) As Boolean
            
    Public Declare Function CeCreateFile Lib "rapi.dll" ( _
        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 "rapi.dll" ( _
        lpVersionInformation As CEOSVERSIONINFO) As Boolean
            
    Public Declare Function CeRapiInitEx Lib "rapi.dll" ( _
        pRapiInit As RAPIINIT) As Long
        
    Public Declare Function CeRapiUninit Lib "rapi.dll" () As Long
    
    Public Declare Function CeReadFile Lib "rapi.dll" ( _
        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 "rapi.dll" ( _
        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 "rapi.dll" () 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 = "Bytes Copied:" & _
                        (BytePos - 1) & " Up."
                        
                Form1.Label6.Refresh
            Loop
            Form1.Label6.Caption = Form1.Label6.Caption & _
                    " Transfer Completed."
                    
        Else
            lResult = CeCloseHandle(lCeFileHandle)
            MsgBox "Device File Does Not Exist Or Is Empty (0 Bytes)!"
        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 = "Bytes Copied: " & _
                            TotalCopied & " Down."
                            
                    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 = "Bytes Copied: " & _
                            TotalCopied & " Down."
                            
                    Form1.Label6.Refresh
                    Exit Do
                End If
            Loop
        Else
            'CeCreateFile failed.  Why?
            Select Case CeGetLastError
                Case ERROR_FILE_EXISTS
                    MsgBox "A file already exists with the specified name."
                Case ERROR_INVALID_PARAMETER
                    MsgBox "A parameter was invalid."
                Case ERROR_DISK_FULL
                    MsgBox "Disk if Full."
                Case Else
                    MsgBox "An unknown error occurred."
            End Select
        End If
        Form1.Label6.Caption = Form1.Label6.Caption & " Transfer Completed."
        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 & "." & _
                ceosver.dwMinorVersion & "." & _
                ceosver.dwBuildNumber & " " & _
                Left$(ceosver.szCSDVersion, _
                InStr(ceosver.szCSDVersion, Chr$(0)) - 1)
        Else
            RapiGetCEOSVersionString = ""
        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 <> ""
    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("autoexec.bat") Then...
    
        Dim I As Integer
        
        On Error Resume Next
        
        I = Len(Dir$(sFilename))
        If Err Or I = 0 Or Trim(sFilename) = "" Then
            FileExists = False
        Else
            FileExists = True
        End If
    End Function
    					
  6. Run the project.
  7. After you make sure that the Windows CE device is connected to the desktop computer through ActiveSync, click the Connect button.
  8. 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.
  9. Click Copy Up to Desktop. Notice that the file is copied to the desktop.

REFERENCES

For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:

249144 How to identify the CE device connected to the desktop machine

306368 How to use RAPI to add keys and values to the registry on a remote Windows CE device


Modification Type:MinorLast Reviewed:12/27/2004
Keywords:kbhowto KB307256