Home » excel » C#. Excel Addin. Can't reposition floating custom task pane

C#. Excel Addin. Can't reposition floating custom task pane

Posted by: admin April 23, 2020 Leave a comment

Questions:

When creating a custom task pane (_CustomTaskPane MSDN) and setting its DockPosition to floating, I want to specify the Top and Left properties of the window appeared. As Office COM APIs do not provide direct possibility to do this, people advise to alter the values of corresponding properties of CommandBar:

var application = (_Application)_nativeTaskPane.Application;
application.CommandBars["Task Pane Title"].Top = top;
application.CommandBars["Task Pane Title"].Left = left;

In the code above I assume that

1) _nativeTaskPane is my instance implementing _CustomTaskPane (actually it is Microsoft.Office.Core.CustomTaskPane)

2) _Application is Microsoft.Office.Interop.Excel._Application

Of course, I’m doing it after setting Visible = true. Even subscribed to task pane’s VisibleStateChange to be more sure. However I’m getting a COMException with the HRESULT E_FAILED.

The thing is I can read these properties (Top & Left) when debugging, however setting them throws exception.

Looks like the issue popped up in the internet at least several times:

1) http://www.add-in-express.com/forum/read.php?FID=1&TID=5595

2) [http://aritrasaha.wordpress.com/2009/05/19/programatically-position-office-2007-floating-custom-task-pane/]

3) [http://www.visualstudiodev.com/visual-studio-tools-for-office/need-location-of-custom-task-pane-45822.shtml]

The workaround is using Windows API. However, can anyone explain what can be wrong with using CommandBar-approach? Maybe I can “reconfigure” smth for this Top/Left-setters to work without exceptions.

How to&Answers:

this is the solution I use in my programs:

    /// <summary>
    /// Set a custom panes position in the undocked state.
    /// </summary>
    /// <param name="customTaskPane">The custom task pane.</param>
    /// <param name="x">The new X position.</param>
    /// <param name="y">The new Y position.</param>
    private void SetCustomPanePositionWhenFloating(CustomTaskPane customTaskPane, int x, int y)
    {
        var oldDockPosition = customTaskPane.DockPosition;
        var oldVisibleState = customTaskPane.Visible;

        customTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionFloating;
        customTaskPane.Visible = true; //The task pane must be visible to set its position

        var window = FindWindowW("MsoCommandBar", customTaskPane.Title); //MLHIDE
        if (window == null) return;

        WinApi.MoveWindow(window, x, y, customTaskPane.Width, customTaskPane.Height, true);

        customTaskPane.Visible = oldVisibleState;
        customTaskPane.DockPosition = oldDockPosition;
    }

    [DllImport("user32.dll", EntryPoint = "FindWindowW")]
    public static extern System.IntPtr FindWindowW([System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpClassName, [System.Runtime.InteropServices.InAttribute()] [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] string lpWindowName);

    [DllImport("user32.dll", EntryPoint = "MoveWindow")]
    [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
    public static extern bool MoveWindow([System.Runtime.InteropServices.InAttribute()] System.IntPtr hWnd, int X, int Y, int nWidth, int nHeight, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)] bool bRepaint);



    /// <summary>
    /// Set a custom panes size in the undocked state.
    /// </summary>
    /// <param name="customTaskPane">The custom task pane.</param>
    /// <param name="width">The new width.</param>
    /// <param name="height">The new height.</param>
    private void SetCustomPaneSizeWhenFloating(CustomTaskPane customTaskPane, int width, int height)
    {
        var oldDockPosition = customTaskPane.DockPosition;

        customTaskPane.DockPosition = Microsoft.Office.Core.MsoCTPDockPosition.msoCTPDockPositionFloating;
        customTaskPane.Width = width;
        customTaskPane.Height = height;

        customTaskPane.DockPosition = oldDockPosition;
    }

Feel free to use it… 🙂

Regards,
Jörg

Answer:

It should work and there is an interesting comment by MVP Cindy Meister regarding this error here (she tested that it works before answering this forum question) – http://social.msdn.microsoft.com/Forums/vstudio/en-US/2df0e430-4d93-416e-89a0-56f8ad5dc988/seting-position-of-a-floating-custome-task-pane?prof=required

In it, she says that using the wrong variable to get the application object causes the error ie:

Globals.MyAddIn.Application -> this will ultimately cause an exception   
Globals.ThisAddin.Application -> this will ultimately work

Where we assume that both return the same Application object.

If you think that’s bizarre, then you’re in good company.

I’ve added a comment to the question that asks why would the name of the variable used to access the Application object make any difference – surely it’s the same Application object being used.

I suspect it’s some scary internal, reflection-like limitation imposed by some other internals. But that the innocent developer is not protected from this very odd scenario.

Answer:

I think that once a custom pane is set to floating you can’t change its top/left properties by definition. what exactly do you want to achieve? do you want to position the pane on specific position? if yes, do it before you set the visibleproperty to true

Answer:

The Commandbar you should be referencing is “Task Pane” which is a standard CommandBar in the CommandBars collection. You got the HRESULT message because the “Task Pane Title” CommandBar was not found in the CommandBars collection.