Virtual Channel Client (Windows Embedded CE 6.0)

1/6/2010

The client part of a virtual channels client/server application is a dynamic-link library (DLL). This client DLL is loaded during Terminal Services initialization on the client computer. You must also register the DLL on the client computer. For more information, see Virtual Channel Client Registration.

The system can support one or more virtual channels, up to a maximum of CHANNEL_MAX_COUNT, which is currently defined as 30. Microsoft provides virtual channel client applications for both clipboard redirection and printer redirection, which leaves a maximum of 28 virtual channels that can be supplied by the OEM.

To run the server application, the client DLL exports a VirtualChannelEntry function.

During initialization, Terminal Services calls VirtualChannelEntry to pass a set of function pointers to the client DLL. Then, the client calls these functions to work with virtual channels. The function pointers are in a CHANNEL_ENTRY_POINTS structure. This structure contains pointers to the four functions that the client DLL calls to access virtual channels. The following table shows these four functions.

Function Description

VirtualChannelInit

Registers the names of the virtual channels to be used by the client and provides a VirtualChannelInitEvent callback through which Terminal Services notifies the client about events that affect the client connection.

VirtualChannelOpen

Opens the client end of a specified virtual channel and provides a VirtualChannelOpenEvent callback through which Terminal Services notifies the client about events that affect the virtual channel.

VirtualChannelWrite

Writes data to a virtual channel. Terminal Services sends this data to the server end of the virtual channel. The server end calls WTSVirtualChannelRead to read the data.

VirtualChannelClose

Closes a virtual channel.

Create the Virtual Channel Client DLL

To access virtual channels from a Windows Embedded CE powered device, you must create a virtual-channel client DLL that includes function implementations for VirtualChannelEntry and for the event callback functions, VirtualChannelInitEvent and VirtualChannelOpenEvent. Your function implementations must also support the custom functionality of your virtual channel application. For example, you must specify the type of data to send to a server in your function implementations.

Ee484718.collapse(en-US,WinEmbedded.60).gifInitialize Access to a Virtual Channel to Send Data

The VirtualChannelEntry function is the entry-point function called by the server application. In your virtual channel client DLL, the VirtualChannelEntry function implementation must include a call to the VirtualChannelInit function to initialize virtual channel access. You can use the VirtualChannelInit function pointer that you received in the PCHANNEL_ENTRY_POINTS structure to make this call. When you call VirtualChannelInit, the pChannel parameter must contain the names of the virtual channels you want to register. When you call VirtualChannelInit, you must also pass a pointer to your VirtualChannelInitEvent callback function in pChannelInitEventProc.

After VirtualChannelEntry is called by the server application, you must copy the PCHANNEL_ENTRY_POINTS structure into a private buffer, because otherwise the system may delete this structure from memory.

Terminal Services calls this callback function as soon as initialization has been completed, and then calls it again when a connection has been established by using a Terminal Server.

The following example code shows an implementation of VirtualChannelEntry.

#include <stdafx.h>
#include <cchannel.h>

HANDLE ClientHandle = NULL;
CHANNEL_DEF pChannel[10];

PCHANNEL_ENTRY_POINTS pEntryPoints;
CHANNEL_ENTRY_POINTS SavedEntryPoints;
PCHANNEL_INIT_EVENT_FN pChannelInitEventProc;

BOOL VCAPITYPE VirtualChannelEntry( PCHANNEL_ENTRY_POINTS pEntryPoints);
{
      UINT retval = 0;
      strcpy(pChannel[0].name, "MyVChannel");
      pChannel[0].options = CHANNEL_OPTION_ENCRYPT_RDP;
      pChannelInitEventProc = VirtualChannelInitEvent;

      // call VirtualChannelInit using the function pointer in
      // PCHANNEL_ENTRY_POINTS
      retval = pEntryPoints->pVirtualChannelInit (&ClientHandle,
                        pChannel, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
                        pChannelInitEventProc);

      memcpy(&SavedEntryPoints, pEntryPoints,
              sizeof(CHANNEL_ENTRY_POINTS);
      return TRUE;
}

When VirtualChannelInit returns, the options member of each CHANNEL_DEF structure is set to CHANNEL_OPTION_INITIALIZED if the channel was successfully initialized.

Ee484718.collapse(en-US,WinEmbedded.60).gifOpen a Virtual Channel

The VirtualChannelInitEvent function implementation must handle the various types of events that the server can pass into the event parameter. When a notification of the CHANNEL_EVENT_CONNECTED event is received by this callback function, it indicates that the connection is established, and you can call the VirtualChannelOpen function to open the virtual channels that you registered by the VirtualChannelInit call. You can use the VirtualChannelOpen function pointer received in the PCHANNEL_ENTRY_POINTS structure to make this call.

The VirtualChannelOpen call takes a pointer to the VirtualChannelOpenEvent callback function. The VirtualChannelOpenEvent function implementation must handle the events that can occur on an open channel. These events are passed into the event parameter.

The following example code shows an implementation of the VirtualChannelInitEvent callback function.

#include <stdafx.h>
#include <cchannel.h>

HANDLE ChannelHandle = NULL;

PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc;
UINT retval;
UINT pClientID = 7530;
UINT pUserData = 1;

VOID VCAPITYPE VirtualChannelInitEvent( LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength);
{
     switch (event)
     {
     case CHANNEL_EVENT_CONNECTED;

          // client has connected to the server
          // pointer to the VirtualChannelOpenEvent callback function
          pChannelOpenEventProc = VirtualChannelOpenEvent;

          // Call VirtualChannelOpen using the function pointer in
          // CHANNEL_ENTRY_POINTS
          retval = SavedEntryPoints.pVirtualChannelOpen(pInitHandle, (LPDWORD)&ChannelHandle,"MyVChannel", 
      pChannelOpenEventProc);
          if (retval == CHANNEL_RC_OK)
            {
               SaveEntryPoints.pVirtualChannelWrite(&ChannelHandle,
                   pClientID, sizeof(pClientID), pUserData);
            }

            break;
      case CHANNEL_EVENT_DISCONNECTED:
            //client logged off the server
            break;
      case CHANNEL_EVENT_INITIALIZED:
            //RDP is ready
            break;
      case CHANNEL_EVENT_TERMINATED:
             //client is disconnected from server
            // Call VirtualChannelClose using the function pointer in   
            // CHANNEL_ENTRY_POINTS
           SavedEntryPoints.pVirtualChannelClose((DWORD)ChannelHandle);
           ChannelHandle = NULL;
           break;
     }
}

Ee484718.collapse(en-US,WinEmbedded.60).gifSend Data to a Server Through a Virtual Channel

After the VirtualChannelOpen call returns, you can call the VirtualChannelWrite function to send the desired data through the virtual channel to the server. Again, you can use the VirtualChannelWrite function pointer in the PCHANNEL_ENTRY_POINTS structure to make this call. The write operation is asynchronous. Therefore, you must not release or reuse the buffer that is passed to VirtualChannelWrite until Terminal Services calls your VirtualChannelOpenEvent function to indicate that the write operation has been completed.

When you call VirtualChannelWrite to send pData to the server, you can also pass a piece of user-defined data in pUserData that identifies the write operation. Terminal Services passes this user-defined data back to the client when it calls VirtualChannelOpenEvent to notify the client that the write operation has been completed. At the server end of the virtual channel, when the data sent through pData is received, the server add-in calls the WTSVirtualChannelRead function to read the data.

Ee484718.collapse(en-US,WinEmbedded.60).gifSend Data to a Client Through a Virtual Channel

Terminal Services also calls your VirtualChannelOpenEvent callback function when data is written to the virtual channel through the server component. The server component calls the WTSVirtualChannelWrite function to write data to the buffer at the server-end of the virtual channel.

The client and server components can write any size data blocks to the virtual channel. However, before you send the data, Terminal Services breaks the data into segments of CHANNEL_CHUNK_LENGTH bytes. Then, Terminal Services calls your VirtualChannelOpenEvent function one time for each data segment, instead of rebuilding the data into a block of the original size. Each call to VirtualChannelOpenEvent indicates the size of the segment, indicates the total size written by the server, and indicates whether the data is the beginning, middle, or end of a block written by the server.

The following example code shows an implementation of the VirtualChannelOpenEvent callback function.

#include <stdafx.h>
#include <cchannel.h>

VOID VCAPITYPE VirtualChannelOpenEvent( DWORD openHandle, UINT event, LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlag);
{
     switch (event)
     {
     case CHANNEL_EVENT_DATA_RECEIVED:
          // the virtual channel received data from the server
          break;

     case CHANNEL_EVENT_WRITE_CANCELLED:
          // the write operation has been canceled.
          break;
     case CHANNEL_EVENT_WRITE_COMPLETE:
          // the write operation has been completed. The client ID data
          // was received by the server.
          break;
     }
     return;
}

Ee484718.collapse(en-US,WinEmbedded.60).gifClose a Virtual Channel

You can call VirtualChannelClose to close a virtual channel. You can use the VirtualChannelClose function pointer received by the PCHANNEL_ENTRY_POINTS structure to make this call. However, you do not have to explicitly call it, because Terminal Services automatically closes all channels when the client disconnects from the server.

When a Terminal Services client disconnects from the server, a CHANNEL_EVENT_DISCONNECTED message is sent. When the Terminal Services client terminates, a CHANNEL_EVENT_TERMINATED message is sent.

Load the Virtual Channel Client DLL

One way that you can load a custom virtual channel client DLL to execute its unique client/server functionality is by using the C/C++ interfaces. You can obtain an interface pointer to the Remote Desktop ActiveX Control and use its methods, such as IMsTscAdvancedSettings::put_PluginDlls and IMsTscSecuredSettings::put_StartProgram. For more information, see Remote Desktop ActiveX Control Interfaces.

You must register the virtual channel client DLL and the server application before you load it. For more information, see Virtual Channel Client Registration and Virtual Channel Server Registration.

See Also

Concepts

Virtual Channels Implementation

Other Resources

Creating a New Subproject