How to: Add an application sharing view to your application

Lync 2013

Learn about how to add a Microsoft Lync 2013 API application sharing view object to your application to view shared applications in Microsoft Lync 2013 UI suppression mode.

Last modified: July 19, 2013

Applies to: Lync 2013

The application sharing view object gives your UI suppressed and Lync 2013 API-enabled application a sharing view feature with the same capabilities as the sharing stage in the Lync client. In order to use the application sharing view object, you need to create a container control in your window and then dock the application viewer into the container. As the shared application dimensions change, your container and the application sharing view need to react by re-dimensioning in turn.

This topic shows you how to dock an application sharing view in your application and react to resizing events generated by the application sharing view. The sample code in this topic is taken from a sample that you can download from code.msdn.microsoft.com. In figure 1, the sample is shown hosting a Lync conversation and showing the Notepad.exe process that is being shared by the person on the remote side of the conversation.

Figure 1. A resource sharing application with docked application sharing view.

UI suppression application with sharing stage

The prerequisites for viewing a shared resource in UI suppression are as follows:

  • Microsoft Lync 2013 must be installed and running on the development computer.

  • You must have sign-in credentials for Microsoft Lync Server 2013.

  • Microsoft Lync 2013 SDK must be installed on the development computer.

Core concepts to know

Topic

Description

Sharing resources in a conversation

Learn about programmatically sharing a computer monitor, desktop, or running program with another Lync 2013 user in a conversation window by using classes in Microsoft Lync 2013 SDK.

Application sharing modality

Learn about the ApplicationSharingModality class and how it enables you to share resources in an application.

Application sharing for UI suppression mode

Learn about using the Microsoft Lync 2013 SDK to give your application a shared resource view feature while in Microsoft Lync 2013 UI suppression mode.

How to: Sign a user in to Lync

Learn how to sign in a client application to Microsoft Lync 2013, sign out a user of Lync 2013, and shut the Lync 2013 process down with UI suppression enabled.

How to: Start a resource sharing conversation

Learn how to use Microsoft Lync 2013 SDK to start a Microsoft Lync 2013 sharing conversation and get a list of shareable resources that are shared in the conversation.

In order to return your window and docking container control to their original dimensions after the resource viewer is either closed or resized, you should cache the dimensions of these objects when your window is opened. The following example declares a structure to hold this cached information.

    internal struct ControlDimensions
    {
        /// <summary>
        /// Form and panel starting dimensions 
        /// </summary>
        internal int _originalFormWidth;
        internal int _originalFormHeight;
        internal int _horizontalMargin;
        internal int _verticalMargin;
        internal int _originalPanelWidth;
        internal int _originalPanelHeight;

    }

The following class field declarations are used by the application logic in this topic

        /// <summary>
        /// Dimensions of the parent form and container control that
        /// will dock the application sharing view
        /// </summary>
        /// 
        ControlDimensions _windowSize;

        /// <summary>
        /// The Application sharing modality of the conversation itself
        /// </summary>
        ApplicationSharingModality _sharingModality;


Setting initial application state

Use the form load event to set values in the previously declared ControlDimensions structure. The panel width and height set in this example is an arbitrary value that works for the sample application and is used to set the width and height of the panel at runtime.

        /// <summary>
        /// invoked when sample form is loaded. Initializes fields, gets API entry point, 
        /// registers for events on Lync Client and ConversationManager.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShareResources_Form_Load(object sender, EventArgs e)
        {
            _windowSize = new ControlDimensions();
            _windowSize._originalFormHeight = this.Height;
            _windowSize._originalFormWidth = this.Width;
            _windowSize._originalPanelHeight = 600;
            _windowSize._originalPanelWidth = 975;
        }

The following tasks show you how to implement a visual shared resource viewer in your Lync 2013 API-enabled application

You can get the viewer object at any time after you get the application sharing modality object from the conversation, but the viewer does not show content until the application sharing modality is connected. The code in the following task should be added in the Modality.ModalityStateChanged event handler for the application sharing modality.

Registering for application sharing modality state change events

Register for the Modality.ModalityStateChanged event when the new conversation is started. The ConversationManager.ConversationAdded event is raised when a conversation is started.

To register for the application sharing modality state change event

  1. Register an event callback method for the ConversationManager.ConversationAdded event.

  2. When a new conversation is added, register an event callback method for the Modality.ModalityStateChanged event.

    The following example handles the ConversationManager.ConversationAdded event.

    Important note Important

    This example shows only the code that you need for application sharing modality event handling. See How to: Start a resource sharing conversation for a more complete example of a ConversationAdded event handler.

    
            void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
            {
    
                //Get the application sharing modality from the new conversation and cache it in a class field
                _sharingModality = (ApplicationSharingModality)e.Conversation.Modalities[ModalityTypes.ApplicationSharing];
    
                //Register for state changes like connecting->connected
                _sharingModality.ModalityStateChanged += _sharingModality_ModalityStateChanged;
            }
    
    

Handling application sharing modality state change events

Create a container control and dock the Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingView object when the conversation Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingModality is connected in the conversation. You can dispose of the container control when the conversation application sharing modality is disconnected after a user closes the sharing stage or leaves the conversation.

To handle the application sharing modality state changed event

  1. Get the application sharing modality that raised the state change event

    The following example docks the application sharing viewer when the new state of the application sharing modality is connected.

                //Modality will be connected for each particpant whethere they have accepted the sharing invite or not.
                ApplicationSharingModality thisModality = (ApplicationSharingModality)sender;
    
    
  2. Check to see if the new modality state is Microsoft.Lync.Model.Conversation.ModalityState.Connected.

                if (e.NewState == ModalityState.Connected)
                {
    
    
  3. Check to see if this application sharing modality is owned by the conversation object itself.

                    if (thisModality == _conversation.Modalities[ModalityTypes.ApplicationSharing])
                    {
    
    
  4. Find out if the shared application is owned by the self participant. You can’t view a locally shared application resource.

                        if (thisModality.Sharer != _conversation.SelfParticipant)
                        {
    
    
  5. If the shared resource is not the self participant’s resource, then create a panel control and dock the Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingView.

    this.Invoke(new NoParamDelegate(DockAppShareView));
    

The following example shows the complete modality state changed event callback method.

        /// <summary>
        /// Handles the even raised when the state of an application sharing modality changes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _sharingModality_ModalityStateChanged(object sender, ModalityStateChangedEventArgs e)
        {
            //Modality will be connected for each particpant whethere they have accepted the sharing invite or not.
            ApplicationSharingModality thisModality = (ApplicationSharingModality)sender;
            if (e.NewState == ModalityState.Connected)
            {
                if (thisModality == _conversation.Modalities[ModalityTypes.ApplicationSharing])
                {
                    //If the local user is not resource sharer, then dock the view to see
                    //the resource shared by a remote user
                    if (thisModality.Sharer != _conversation.SelfParticipant)
                    {
                        this.Invoke(new NoParamDelegate(DockAppShareView));
                    }
                }
            }
            if (e.NewState == ModalityState.Disconnected)
            {
                if (thisModality == _conversation.Modalities[ModalityTypes.ApplicationSharing])
                {
                    this.Invoke(new NoParamDelegate(RemoveDockingPanel));
                }
            }
        }

Showing the viewer in your application window involves getting the handle of the container control that you are docking the viewer into and then calling the ApplicationSharingView.SetParent method.

To dock the viewer

  1. Register for the ApplicationSharingView.PropertyChanged event.

  2. Get the Handle of the control that will contain the application sharing view. In the following example, a Panel control is created at run-time and then the parent window is resized to fit the panel.

  3. Call the ApplicationSharingView.SetParent method.

The following example registers for the application sharing viewer events that an application uses to respond to viewer size changes and then docks the viewer by providing the handle of the parent container control to the viewer by calling the ApplicationSharingView.SetParent method.

        /// <summary>
        /// Docks the application sharing view in a container control and then
        /// registers for view events
        /// </summary>
        private void DockAppShareView()
        {

            //Register for application sharing view events.
            _sharingModality.View.PropertyChanged += View_PropertyChanged;
            _sharingModality.View.StateChanged += View_StateChanged;
            try
            {
                //Expand the width of the WinForm to contain the new view panel.
                //Width of WinForm is expanded by width of the panel plus 6 pixels
                this.Width += _windowSize._originalPanelWidth + 6;

                //Get the horizontal and vertical panel margins to preserve
                _windowSize._verticalMargin = this.Height - _windowSize._originalPanelHeight;
                _windowSize._horizontalMargin = this.Width - _windowSize._originalPanelWidth;


                //Instantiate the new panel and set various properties
                _ViewPanel = new Panel();
                _ViewPanel.SuspendLayout();
                this.SuspendLayout();

                _ViewPanel.BackColor = System.Drawing.Color.WhiteSmoke;
                _ViewPanel.Anchor = ((
                    System.Windows.Forms.AnchorStyles)(
                    (
                        (
                            System.Windows.Forms.AnchorStyles.Top
                            | System.Windows.Forms.AnchorStyles.Left
                        )
                    )
                ));

                _ViewPanel.Location = new System.Drawing.Point(415, 26);
                _ViewPanel.Size = new System.Drawing.Size(_windowSize._originalPanelWidth, _windowSize._originalPanelHeight);


                _ViewPanel.TabIndex = 1;


                //Add the new panel to the form
                this.Controls.Add(_ViewPanel);
                _ViewPanel.Visible = true;
                _ViewPanel.ResumeLayout(false);
                _ViewPanel.PerformLayout();
                this.ResumeLayout(false);
                this.PerformLayout();

                //Set the handle of the panel as the parent of the view
                _sharingModality.View.SetParent((int)_ViewPanel.Handle);

            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine("Unauthorized access in DocAppShareView " + ex.Message);
            }

        }


The default mode of the viewer is Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewDisplayMode.FitToParent. In this mode, changes in the dimensions of the shared resource are handled by changing the resolution of the viewer without changing the dimensions of the viewer. If you are concerned that a user will not be able to read text in a shared resource at high resolution, you should set the display mode of the viewer to Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewDisplayMode.ActualSize. In this mode, the original resolution of the shared resource is preserved when its dimensions change. The dimension changed is handled by resizing the viewer.

To set the viewer mode

  1. Get the user’s display mode choice and set the ApplicationSharingView.DisplayMode property to the Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewDisplayMode enumerator for the chosen mode.

            /// <summary>
            /// Changes the view mode of the application sharing view
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void autoSizeView_Checkbox_CheckedChanged(object sender, EventArgs e)
            {
                //this throws an exception if you are sharing out the local resource. Only use this
                //call if you are viewing a remote resource.
                if (_sharingModality.LocalSharedResources.Count > 0)
                {
                    return;
                }
    
                try
                {
                    CheckBox fitToParent_checkBox = (CheckBox)sender;
                    if (fitToParent_checkBox.Checked == true)
                    {
                        _sharingModality.View.DisplayMode = ApplicationSharingViewDisplayMode.FitToParent;
                    }
                    else
                    {
                        _sharingModality.View.DisplayMode = ApplicationSharingViewDisplayMode.ActualSize;
                    }
                    _sharingModality.View.SyncRectangle();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Exception on auto size sync rectangle: " + ex.Message);
                }
            }
    
    
  2. Re-sync the viewer.

    Caution note Caution

    You cannot re-sync the viewer until you have docked it in a container. Trying to sync an un-docked view throws an exception.

    
                //If viewer has a parent window, then it can be resynched.
                if (_sharingModality.View.Properties[ApplicationSharingViewProperty.ParentWindow] != null)
                {
                    _sharingModality.View.SyncRectangle();
                }
    
    

If the ApplicationSharingView.DisplayMode property value is Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewDisplayMode. ActualSize, the ApplicationSharingView dimensions are free to be resized as the shared application is resized. In order to keep the full application sharing view visible, resize the container control and application window to accommodate the new dimensions of the view.

The person who is sharing a resource such as Notepad.exe may use the mouse to drag a corner of the notepad to expand or shrink the notepad. When this happens, the viewer raises the ApplicationSharingView.PropertyChanged event. The changed properties of the viewer are the dimensional properties, height and width.

To respond to viewer dimension changes

  1. Check the display mode of the viewer. If it is Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewDisplayMode.FitToParent, then you can return from the event callback method after setting the container and application window to their original dimensions.

                    //If user chose FitToParent, the parent container control is reset to original dimensions. 
                    if (_sharingModality.View.DisplayMode == ApplicationSharingViewDisplayMode.FitToParent)
                    {
                        this.Invoke(new NoParamDelegate(ResetFormToOriginalDimensions));
    
                        return;
                    }
    
    
  2. Check the view properties that are changed. If the properties are Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewProperty.Height or Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingViewProperty.Width, then the view dimensions have changed.

                //If the changed viewer property is a dimension property then resize parent container control
                if (e.Property == ApplicationSharingViewProperty.Height || e.Property == ApplicationSharingViewProperty.Width)
                {
    
    
  3. Change the dimensions of the parent container to fit the view.

The following example re-sizes the container control and the main form when the dimensions of the viewer change.

        /// <summary>
        /// Sets dimensions for container control parent of application sharing view when the 
        /// dimensions of the view change
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void View_PropertyChanged(object sender, ApplicationSharingViewPropertyChangedEventArgs e)
        {
            ApplicationSharingView view = (ApplicationSharingView)sender;
            if (view.Properties == null)
            {
                return;
            }

            //If the changed viewer property is a dimension property then resize parent container control
            if (e.Property == ApplicationSharingViewProperty.Height || e.Property == ApplicationSharingViewProperty.Width)
            {
                //If user chose FitToParent, the parent container control is not resized. 
                if (_sharingModality.View.DisplayMode == ApplicationSharingViewDisplayMode.FitToParent)
                {
                    this.Invoke(new NoParamDelegate(ResetFormToOriginalDimensions));

                    return;
                }
                

                this.Invoke(
                    new ResizeFormForPanelDelegate(ResizeFormForPanel), 
                    new object[] { view });
            }
            else if (e.Property == ApplicationSharingViewProperty.ParentWindow)
            {
                if (_sharingModality.View.State == ApplicationSharingViewState.Active)
                {
                    _sharingModality.View.SyncRectangle();
                }

            }
        }

The following example gets the dimensions of an ApplicationSharingView and then resizes the parent container control and the application window to show the panel control. First, the width of panel and window are set and then their height is set. The new dimensions of panel and window can be any of:

  • The original size of the window + panel, if the view dimensions are small enough to fit this size

  • The maximum size allowed, based on the screen working area

  • An intermediate size that is large enough to preserve left and right window/panel margins.

        private delegate void ResizeFormForPanelDelegate(ApplicationSharingView view);
        /// <summary>
        /// Changes the dimensions of the main form and container control to fit
        /// the new size of the viewer. The maximum dimensions of the form are 
        /// constrained by the dimensions of the screen work area.
        /// </summary>
        /// <param name="newHeight">int. The new height of the viewer</param>
        /// <param name="newWidth">int. The new width of the viewer</param>
        private void ResizeFormForPanel(ApplicationSharingView view)
        {

            //Add 4 pixels to prevent scroll bars from appearing on container.
            int newViewWidth = (int)view.Properties[ApplicationSharingViewProperty.Width] + 4;
            int newViewHeight = (int)view.Properties[ApplicationSharingViewProperty.Height] + 4;

            //Get the maximum possible dimensions as constrained by the screen
            int screenHeight = SystemInformation.WorkingArea.Height;
            int screenWidth = SystemInformation.WorkingArea.Width;


            //If the original width of the form is less than the 
            //proposed new width, then widen the form to fit the new
            //panel dimensions
            if (_windowSize._originalFormWidth < (newViewWidth + _windowSize._horizontalMargin))
            {
                //If the proposed width is less than or equal to the
                //working area of the desktop, set the width to the 
                //proposed width
                if ((newViewWidth + _windowSize._horizontalMargin) <= screenWidth)
                {
                    _ViewPanel.Width = newViewWidth;
                    this.Width = newViewWidth + _windowSize._horizontalMargin;
                }
                else
                {
                    //Set the form to maximum width
                    _ViewPanel.Width = screenWidth - _windowSize._horizontalMargin;
                    this.Width = screenWidth;
                }
            }
            //Otherwise set the form to its original width.
            else
            {
                this.Width = _windowSize._originalFormWidth;
                _ViewPanel.Width = _windowSize._originalPanelWidth;
            }


            //If the original Height of the form is less than the 
            //proposed new height then set the height of the form to
            //the new height
            if (_windowSize._originalFormHeight < (newViewHeight + _windowSize._verticalMargin))
            {
                //If the proposed height is less than or equal to the
                //working area of the desktop, set the height to the 
                //proposed height
                if ((newViewHeight + _windowSize._verticalMargin) <= screenHeight)
                {
                    _ViewPanel.Height = newViewHeight;
                    this.Height = newViewHeight + _windowSize._verticalMargin;
                }
                else
                {
                    _ViewPanel.Height = screenHeight - _windowSize._verticalMargin;
                    this.Height = screenHeight;
                }

            }
            else
            {
                this.Height = _windowSize._originalFormHeight;
                _ViewPanel.Height = _windowSize._originalPanelHeight;
            }
            //Resynchronize the view if it is docked in a parent container
            if (_sharingModality.View.Properties[ApplicationSharingViewProperty.ParentWindow] != null)
            {
                _sharingModality.View.SyncRectangle();
            }
        }

This example resets the application window and container panel to the dimensions saved in the form load event.

        /// <summary>
        /// resets the main window to the original dimensions for displayed
        /// view panel
        /// </summary>
        private void ResetFormToOriginalDimensions()
        {
            this.Width = _windowSize._originalFormWidth;
            _ViewPanel.Width = _windowSize._originalPanelWidth;
            this.Width += _windowSize._originalPanelWidth + 6;
            this.Height = _windowSize._originalFormHeight;
            _ViewPanel.Height = _windowSize._originalPanelHeight;

        }

Show: