Expose VSTO functionality to VBA w/o local admin

你说的曾经没有我的故事 提交于 2019-12-06 08:15:25

If I may interpret your question as broadly as "How do I expose functionality in a .Net assembly to Excel without COM registration" then an excellent solution is to use Excel's XLL interface. Basically one deploys an xll shim and an associated .Net dll. When the xll is loaded it reflects over the dll and exposes the functions therein to Excel.

An open source implementation can be found here http://exceldna.typepad.com/blog/2006/01/introducing_exc.html

A commercial, closed source, but more feature rich one here http://www.managedxll.com/

You can't simply instantiate them as COM objects, as VSTO will not be running in the default application domain.

Here is how I've done it, which is admittedly a bit convoluted. This was with a VSTO workbook saved as an XLA file, which in some ways is more flexible than a pure VSTO add-in.

  • You need to generate a type library using regasm.exe that will be referenced by your VBA code.

  • Create a root factory class in your .NET object model, which is capable of instantiating any of the classes you want to consume in VBA (something like the "Application" class in the Office object models).

  • You then need to find a way to pass a reference to an instance of this factory class to VBA. Once VBA has a reference to an instance of this factory class, it can call its methods to instantiate any other objects in your .NET object model.

  • To pass an instance to VBA, define a macro in your VBA code as follows

Example code:

Private m_objMyFactory As Object

Public Sub RegisterFactory(MyFactory As Object)

    On Error GoTo ErrHandler
    Set m_objMyFactory = MyFactory
    Exit Sub
ErrHandler:
    MsgBox "An unexpected error occurred when registering the Factory component: " & Err.Description
    Exit Sub
End Sub
  • Now add code to the VSTO ThisWorkbook_Open event handler, which instantiates your factory object and calls the above macro passing a reference to the factory object.

Example code:

void ThisWorkbook_Open()
{
     try
     {
         ThisApplication.Run("RegisterFactory",
             new MyNamespace.MyFactory(),
             Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
             Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
             Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
             Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
             Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
             Type.Missing, Type.Missing, Type.Missing, Type.Missing);
     }
     catch (Exception ex)
     {
         MessageBox.Show("Load error: " + ex.ToString());
     }
}

There are a few more issues to consider to get this working robustly - if you're interested in following this up let me know and I'll post more details.

You may be interested in Excel4Net (it is similar to ExcelDNA and ManagedXll, but easier to use):

website: http://www.excel4net.com

blog: http://excel4net.blogspot.com

chiccodoro

Just for reference for future readers: You might also want to have a look to this question:

Accessing a VSTO application-addin types from VBA (Excel)

and, in particular, to the blog that is referenced there:

VSTO Add-ins, COMAddIns and RequestComAddInAutomationService

By overriding RequestComAddInAutomationService() you can expose whatever functionality you want, by defining a Facade class that provides entry points for all those features, and exposing that class to VBA.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!