Pregunta

Estoy probando PowerShell alojamiento con C #. Aquí es una aplicación de consola que funciona:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Office.Interop.Excel;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main()
        {
            Application app = new Application();
            app.Visible = true;
            app.Workbooks.Add(XlWBATemplate.xlWBATWorksheet);

            Runspace runspace = RunspaceFactory.CreateRunspace();
            runspace.Open();
            runspace.SessionStateProxy.SetVariable("Application", app);

            Pipeline pipeline = runspace.CreatePipeline("$Application");

            Collection<PSObject> results = null;
            try
            {
                results = pipeline.Invoke();
                foreach (PSObject pob in results)
                {
                    Console.WriteLine(pob);
                }
            }
            catch (RuntimeException re)
            {
                Console.WriteLine(re.GetType().Name);
                Console.WriteLine(re.Message);
            }
        }
    }
}

La primera vez que se crea una instancia Excel.Application y pasarlo a la instancia PowerShell acogido como un llamado varible $ Aplicación. Funcionado y se puede utilizar esta variable como si Excel.Application fue creado desde dentro de PowerShell.

Me próxima creado un complemento de Excel utilizando VS 2008 y añadido un control de usuario con dos cuadros de texto y un botón para el complemento (el control de usuario aparece como un panel de tareas personalizado al iniciarse Excel). La idea era la siguiente: cuando haga clic en el botón se crea una instancia de PowerShell alojado y me puede pasar a la instancia que Excel.Application actual como una variable, al igual que en la primera muestra, para que pueda utilizar esta variable para automatizar Excel desde PowerShell (un cuadro de texto se utiliza para la entrada y la otra para la salida Aquí está el código:.

using System;
using System.Windows.Forms;

using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Collections.ObjectModel;
using Microsoft.Office.Interop.Excel;

namespace POSHAddin
{
    public partial class POSHControl : UserControl
    {
        public POSHControl()
        {
            InitializeComponent();
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            txtOutput.Clear();

            Microsoft.Office.Interop.Excel.Application app = 
                Globals.ThisAddIn.Application;

            Runspace runspace = RunspaceFactory.CreateRunspace();
            runspace.Open();
            runspace.SessionStateProxy.SetVariable("Application", app);

            Pipeline pipeline = runspace.CreatePipeline(
                "$Application | Get-Member | Out-String");

            app.ActiveCell.Value2 = "Test";

            Collection<PSObject> results = null;
            try
            {
                results = pipeline.Invoke();
                foreach (PSObject pob in results)
                {
                    txtOutput.Text += pob.ToString() + "-";
                }
            }
            catch (RuntimeException re)
            {
                txtOutput.Text += re.GetType().Name;
                txtOutput.Text += re.Message;
            }
        }
    }
}

El código es similar a la primera muestra, salvo que la instancia actual de Excel.Application está disponible para el complemento a través de Globals.ThisAddIn.Application (VSTO genera) y puedo ver que es realmente un Microsoft.Office.Interop. Excel.Application ejemplo, porque se puede usar cosas como app.ActiveCell.Value2 = "Test" (esto realmente pone el texto en la celda activa). Pero cuando pase la instancia Excel.Application a la instancia PowerShell lo que llega allí es una instancia del Sistema .__ ComObject y no puedo encontrar la manera de echarlo a Excel.Application. Cuando examino la variable de PowerShell utilizando $ aplicaciones | Get-Member esta es la salida me meto en el segundo cuadro de texto:

TypeName: System.__ComObject 

Name                        MemberType   Definition 
----                        ----------   ---------- 
CreateObjRef                Method       System.Runtime.Remoting.ObjRef CreateObj... 
Equals                      Method       System.Boolean Equals(Object obj) 
GetHashCode                 Method       System.Int32 GetHashCode()
GetLifetimeService          Method       System.Object GetLifetimeService() 
GetType                     Method       System.Type GetType() 
InitializeLifetimeService   Method       System.Object InitializeLifetimeService() 
ToString                    Method       System.String ToString() 

Mi pregunta es ¿cómo puedo pasar una instancia de Microsoft.Office.Interop.Excel.Application de un VSTO genera complemento de Excel 2007 a una instancia de PowerShell alojada, por lo que puede manipular desde PowerShell?

(He publicado con anterioridad a la pregunta en el foro de Microsoft C # sin respuesta)

¿Fue útil?

Solución

Como keith-hill ha señalado, el problema parece ser que Powershell no puede encontrar información de tipo biblioteca. Una forma de evitarlo es utilizar el método InvokeMember para operar en la instancia System.__ComObject. De esta manera, se puede manipular el objeto directamente. Este post tiene una mejor explicación con ejemplos, aunque utilizando ADSI en lugar de Excel.

Otros consejos

Parece que el tipo que regrese de Globals.ThisAddin.Application es una interacción remota proxy transparente / (System.Runtime.Remoting.Proxies .__ TransparentProxy). Al parecer PowerShell está teniendo dificultades para encontrar la información de biblioteca de tipos para ello.

Lo primero que pensé es que el espacio de ejecución de PowerShell podría no tener el ensamblado de interoperabilidad cargado:

[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.Office.Interop.Excel')

¿Le da un error si se intenta una conversión explícita?

$excel = [Microsoft.Office.Interop.Excel.Application] $Application

También puede ser que funcione en un tema de roscado si el objeto requiere el modo de STA. Con PowerShell v2, es posible que intente lo siguiente:

        Runspace runspace = RunspaceFactory.CreateRunspace();
        runspace.ThreadOptions = PSThreadOptions.UseCurrentThread;
        runspace.Open();
        runspace.SessionStateProxy.SetVariable("Application", app);

O si UseCurrentThread no funciona:

        Runspace runspace = RunspaceFactory.CreateRunspace();
        runspace.ApartmentState = System.Threading.ApartmentState.STA;
        runspace.ThreadOptions = PSThreadOptions.ReuseThread;
        runspace.Open();
        runspace.SessionStateProxy.SetVariable("Application", app);

Puede encontrar más información acerca del uso de STA con PowerShell en este post .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top